2013-02-07 10:34:27 +01:00
|
|
|
/************* TabMySQL C++ Program Source Code File (.CPP) *************/
|
|
|
|
/* PROGRAM NAME: TABMYSQL */
|
|
|
|
/* ------------- */
|
2017-02-16 18:01:48 +01:00
|
|
|
/* Version 2.0 */
|
2013-02-07 10:34:27 +01:00
|
|
|
/* */
|
|
|
|
/* AUTHOR: */
|
|
|
|
/* ------- */
|
2017-02-16 18:01:48 +01:00
|
|
|
/* Olivier BERTRAND 2007-2017 */
|
2013-02-07 10:34:27 +01:00
|
|
|
/* */
|
|
|
|
/* WHAT THIS PROGRAM DOES: */
|
|
|
|
/* ----------------------- */
|
|
|
|
/* Implements a table type that are MySQL tables. */
|
|
|
|
/* It can optionally use the embedded MySQL library. */
|
|
|
|
/* */
|
|
|
|
/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
|
|
|
|
/* -------------------------------------- */
|
|
|
|
/* */
|
|
|
|
/* REQUIRED FILES: */
|
|
|
|
/* --------------- */
|
|
|
|
/* TABMYSQL.CPP - Source code */
|
|
|
|
/* PLGDBSEM.H - DB application declaration file */
|
2016-04-25 00:13:06 +02:00
|
|
|
/* TABMYSQL.H - TABMYSQL classes declaration file */
|
2013-02-07 10:34:27 +01:00
|
|
|
/* GLOBAL.H - Global declaration file */
|
|
|
|
/* */
|
|
|
|
/* REQUIRED LIBRARIES: */
|
|
|
|
/* ------------------- */
|
|
|
|
/* Large model C library */
|
|
|
|
/* */
|
|
|
|
/* REQUIRED PROGRAMS: */
|
|
|
|
/* ------------------ */
|
|
|
|
/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
|
|
|
|
/* */
|
|
|
|
/************************************************************************/
|
2013-06-16 19:07:27 +02:00
|
|
|
#define MYSQL_SERVER 1
|
2013-02-07 10:34:27 +01:00
|
|
|
#include "my_global.h"
|
2013-06-16 19:07:27 +02:00
|
|
|
#include "sql_class.h"
|
|
|
|
#include "sql_servers.h"
|
2021-06-08 17:44:43 +02:00
|
|
|
#if defined(_WIN32)
|
2013-02-07 10:34:27 +01:00
|
|
|
//#include <windows.h>
|
2021-06-08 17:44:43 +02:00
|
|
|
#else // !_WIN32
|
2013-02-07 10:34:27 +01:00
|
|
|
//#include <fnmatch.h>
|
|
|
|
//#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "osutil.h"
|
|
|
|
//#include <io.h>
|
|
|
|
//#include <fcntl.h>
|
2021-06-08 17:44:43 +02:00
|
|
|
#endif // !_WIN32
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Include application header files: */
|
|
|
|
/***********************************************************************/
|
|
|
|
#include "global.h"
|
|
|
|
#include "plgdbsem.h"
|
|
|
|
#include "xtable.h"
|
2017-02-16 18:01:48 +01:00
|
|
|
#include "tabext.h"
|
2013-02-07 10:34:27 +01:00
|
|
|
#include "tabcol.h"
|
|
|
|
#include "colblk.h"
|
2017-02-16 18:01:48 +01:00
|
|
|
//#include "reldef.h"
|
2013-02-07 10:34:27 +01:00
|
|
|
#include "tabmysql.h"
|
|
|
|
#include "valblk.h"
|
2013-05-13 14:48:03 +02:00
|
|
|
#include "tabutil.h"
|
2014-04-19 17:02:53 +02:00
|
|
|
#include "ha_connect.h"
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
#if defined(_CONSOLE)
|
|
|
|
void PrintResult(PGLOBAL, PSEM, PQRYRES);
|
|
|
|
#endif // _CONSOLE
|
|
|
|
|
2014-07-17 18:13:51 +02:00
|
|
|
// Used to check whether a MYSQL table is created on itself
|
2017-05-11 21:57:21 +02:00
|
|
|
bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db,
|
|
|
|
PCSZ tab, PCSZ src, int port);
|
2014-07-17 18:13:51 +02:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* External function. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool ExactInfo(void);
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/* -------------- Implementation of the MYSQLDEF class --------------- */
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Constructor. */
|
|
|
|
/***********************************************************************/
|
|
|
|
MYSQLDEF::MYSQLDEF(void)
|
|
|
|
{
|
|
|
|
Pseudo = 2; // SERVID is Ok but not ROWID
|
|
|
|
Hostname = NULL;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Tabschema = NULL;
|
|
|
|
//Tabname = NULL;
|
|
|
|
//Srcdef = NULL;
|
|
|
|
//Username = NULL;
|
|
|
|
//Password = NULL;
|
2013-02-07 10:34:27 +01:00
|
|
|
Portnumber = 0;
|
2014-04-27 19:18:20 +02:00
|
|
|
Isview = false;
|
|
|
|
Bind = false;
|
|
|
|
Delayed = false;
|
2022-02-07 22:57:24 +01:00
|
|
|
Ignored = false;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Xsrc = false;
|
2014-04-27 19:18:20 +02:00
|
|
|
Huge = false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of MYSQLDEF constructor
|
|
|
|
|
2013-06-16 19:07:27 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Get connection info from the declared server. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name)
|
|
|
|
{
|
|
|
|
THD *thd= current_thd;
|
|
|
|
MEM_ROOT *mem= thd->mem_root;
|
|
|
|
FOREIGN_SERVER *server, server_buffer;
|
|
|
|
DBUG_ENTER("GetServerInfo");
|
|
|
|
DBUG_PRINT("info", ("server_name %s", server_name));
|
|
|
|
|
|
|
|
if (!server_name || !strlen(server_name)) {
|
|
|
|
DBUG_PRINT("info", ("server_name not defined!"));
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "server_name not defined!");
|
2013-06-16 19:07:27 +02:00
|
|
|
DBUG_RETURN(true);
|
|
|
|
} // endif server_name
|
|
|
|
|
|
|
|
// get_server_by_name() clones the server if exists and allocates
|
2014-03-22 08:57:32 +01:00
|
|
|
// copies of strings in the supplied mem_root
|
2013-06-16 19:07:27 +02:00
|
|
|
if (!(server= get_server_by_name(mem, server_name, &server_buffer))) {
|
|
|
|
DBUG_PRINT("info", ("get_server_by_name returned > 0 error condition!"));
|
|
|
|
/* need to come up with error handling */
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "get_server_by_name returned > 0 error condition!");
|
2013-06-16 19:07:27 +02:00
|
|
|
DBUG_RETURN(true);
|
|
|
|
} // endif server
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
DBUG_PRINT("info", ("get_server_by_name returned server at %p",
|
|
|
|
server));
|
2013-06-16 19:07:27 +02:00
|
|
|
|
|
|
|
// TODO: We need to examine which of these can really be NULL
|
|
|
|
Hostname = PlugDup(g, server->host);
|
2017-02-16 18:01:48 +01:00
|
|
|
Tabschema = PlugDup(g, server->db);
|
2013-06-16 19:07:27 +02:00
|
|
|
Username = PlugDup(g, server->username);
|
|
|
|
Password = PlugDup(g, server->password);
|
|
|
|
Portnumber = (server->port) ? server->port : GetDefaultPort();
|
|
|
|
|
|
|
|
DBUG_RETURN(false);
|
|
|
|
} // end of GetServerInfo
|
|
|
|
|
2013-02-22 17:26:08 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Parse connection string */
|
|
|
|
/* */
|
|
|
|
/* SYNOPSIS */
|
|
|
|
/* ParseURL() */
|
|
|
|
/* url The connection string to parse */
|
|
|
|
/* */
|
|
|
|
/* DESCRIPTION */
|
|
|
|
/* Populates the table with information about the connection */
|
|
|
|
/* to the foreign database that will serve as the data source. */
|
|
|
|
/* This string must be specified (currently) in the "CONNECTION" */
|
|
|
|
/* field, listed in the CREATE TABLE statement. */
|
|
|
|
/* */
|
|
|
|
/* This string MUST be in the format of any of these: */
|
|
|
|
/* */
|
|
|
|
/* CONNECTION="scheme://user:pwd@host:port/database/table" */
|
|
|
|
/* CONNECTION="scheme://user@host/database/table" */
|
|
|
|
/* CONNECTION="scheme://user@host:port/database/table" */
|
|
|
|
/* CONNECTION="scheme://user:pwd@host/database/table" */
|
|
|
|
/* */
|
|
|
|
/* _OR_ */
|
|
|
|
/* */
|
|
|
|
/* CONNECTION="connection name" (NIY) */
|
|
|
|
/* */
|
|
|
|
/* An Example: */
|
|
|
|
/* */
|
|
|
|
/* CREATE TABLE t1 (id int(32)) */
|
2013-02-24 01:23:18 +01:00
|
|
|
/* ENGINE="CONNECT" TABLE_TYPE="MYSQL" */
|
2013-02-22 17:26:08 +01:00
|
|
|
/* CONNECTION="mysql://joe:pwd@192.168.1.111:9308/dbname/tabname"; */
|
|
|
|
/* */
|
|
|
|
/* CREATE TABLE t2 ( */
|
|
|
|
/* id int(4) NOT NULL auto_increment, */
|
|
|
|
/* name varchar(32) NOT NULL, */
|
|
|
|
/* PRIMARY KEY(id) */
|
2013-02-24 01:23:18 +01:00
|
|
|
/* ) ENGINE="CONNECT" TABLE_TYPE="MYSQL" */
|
|
|
|
/* CONNECTION="my_conn"; (NIY) */
|
2013-02-22 17:26:08 +01:00
|
|
|
/* */
|
|
|
|
/* 'password' and 'port' are both optional. */
|
|
|
|
/* */
|
|
|
|
/* RETURN VALUE */
|
|
|
|
/* false success */
|
|
|
|
/* true error */
|
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
2013-10-27 10:37:12 +01:00
|
|
|
bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b)
|
2013-02-22 17:26:08 +01:00
|
|
|
{
|
2017-05-11 21:57:21 +02:00
|
|
|
char *tabn, *pwd, *schema;
|
|
|
|
|
2013-02-22 17:26:08 +01:00
|
|
|
if ((!strstr(url, "://") && (!strchr(url, '@')))) {
|
|
|
|
// No :// or @ in connection string. Must be a straight
|
|
|
|
// connection name of either "server" or "server/table"
|
2013-06-16 19:07:27 +02:00
|
|
|
// ok, so we do a little parsing, but not completely!
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((tabn= strchr(url, '/'))) {
|
2014-03-22 08:57:32 +01:00
|
|
|
// If there is a single '/' in the connection string,
|
2013-06-16 19:07:27 +02:00
|
|
|
// this means the user is specifying a table name
|
2017-05-11 21:57:21 +02:00
|
|
|
*tabn++= '\0';
|
2013-06-16 19:07:27 +02:00
|
|
|
|
|
|
|
// there better not be any more '/'s !
|
2017-05-11 21:57:21 +02:00
|
|
|
if (strchr(tabn, '/'))
|
2013-06-16 19:07:27 +02:00
|
|
|
return true;
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Tabname = tabn;
|
2013-06-16 19:07:27 +02:00
|
|
|
} else
|
|
|
|
// Otherwise, straight server name,
|
2014-05-27 12:50:52 +02:00
|
|
|
Tabname = (b) ? GetStringCatInfo(g, "Tabname", Name) : NULL;
|
2013-06-16 19:07:27 +02:00
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2017-02-16 18:01:48 +01:00
|
|
|
htrc("server: %s TableName: %s", url, Tabname);
|
2013-06-16 19:07:27 +02:00
|
|
|
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = url;
|
2013-06-16 19:07:27 +02:00
|
|
|
return GetServerInfo(g, url);
|
2013-02-22 17:26:08 +01:00
|
|
|
} else {
|
|
|
|
// URL, parse it
|
|
|
|
char *sport, *scheme = url;
|
|
|
|
|
|
|
|
if (!(Username = strstr(url, "://"))) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Connection is not an URL");
|
2013-02-22 17:26:08 +01:00
|
|
|
return true;
|
|
|
|
} // endif User
|
|
|
|
|
|
|
|
scheme[Username - scheme] = 0;
|
|
|
|
|
|
|
|
if (stricmp(scheme, "mysql")) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "scheme must be mysql");
|
2013-02-22 17:26:08 +01:00
|
|
|
return true;
|
|
|
|
} // endif scheme
|
|
|
|
|
|
|
|
Username += 3;
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if (!(Hostname = (char*)strchr(Username, '@'))) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "No host specified in URL");
|
2013-02-22 17:26:08 +01:00
|
|
|
return true;
|
2013-08-09 18:02:47 +02:00
|
|
|
} else {
|
2013-02-22 17:26:08 +01:00
|
|
|
*Hostname++ = 0; // End Username
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = Hostname;
|
|
|
|
} // endif Hostname
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((pwd = (char*)strchr(Username, ':'))) {
|
|
|
|
*pwd++ = 0; // End username
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
// Make sure there isn't an extra /
|
|
|
|
if (strchr(pwd, '/')) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL");
|
2013-02-22 17:26:08 +01:00
|
|
|
return true;
|
|
|
|
} // endif
|
|
|
|
|
|
|
|
// Found that if the string is:
|
|
|
|
// user:@hostname:port/db/table
|
|
|
|
// Then password is a null string, so set to NULL
|
2019-08-08 21:52:22 +02:00
|
|
|
if (pwd[0] == 0)
|
2017-05-11 21:57:21 +02:00
|
|
|
Password = NULL;
|
|
|
|
else
|
|
|
|
Password = pwd;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
|
|
|
} // endif password
|
|
|
|
|
|
|
|
// Make sure there isn't an extra / or @ */
|
|
|
|
if ((strchr(Username, '/')) || (strchr(Hostname, '@'))) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL");
|
2013-02-22 17:26:08 +01:00
|
|
|
return true;
|
|
|
|
} // endif
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((schema = strchr(Hostname, '/'))) {
|
|
|
|
*schema++ = 0;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((tabn = strchr(schema, '/'))) {
|
|
|
|
*tabn++ = 0;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2013-10-27 10:37:12 +01:00
|
|
|
// Make sure there's not an extra /
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((strchr(tabn, '/'))) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Syntax error in URL");
|
2013-10-27 10:37:12 +01:00
|
|
|
return true;
|
|
|
|
} // endif /
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Tabname = tabn;
|
2017-02-16 18:01:48 +01:00
|
|
|
} // endif TableName
|
2014-03-22 08:57:32 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Tabschema = schema;
|
|
|
|
} // endif database
|
2013-02-22 17:26:08 +01:00
|
|
|
|
|
|
|
if ((sport = strchr(Hostname, ':')))
|
|
|
|
*sport++ = 0;
|
|
|
|
|
2013-10-27 10:37:12 +01:00
|
|
|
// For unspecified values, get the values of old style options
|
|
|
|
// but only if called from MYSQLDEF, else set them to NULL
|
|
|
|
Portnumber = (sport && sport[0]) ? atoi(sport)
|
2014-04-14 14:26:48 +02:00
|
|
|
: (b) ? GetIntCatInfo("Port", GetDefaultPort()) : 0;
|
2013-04-29 13:50:20 +02:00
|
|
|
|
|
|
|
if (Username[0] == 0)
|
2014-04-14 14:26:48 +02:00
|
|
|
Username = (b) ? GetStringCatInfo(g, "User", "*") : NULL;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
|
|
|
if (Hostname[0] == 0)
|
2014-04-14 14:26:48 +02:00
|
|
|
Hostname = (b) ? GetStringCatInfo(g, "Host", "localhost") : NULL;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
if (!Tabschema || !*Tabschema)
|
|
|
|
Tabschema = (b) ? GetStringCatInfo(g, "Database", "*") : NULL;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
|
|
|
if (!Tabname || !*Tabname)
|
2014-04-14 14:26:48 +02:00
|
|
|
Tabname = (b) ? GetStringCatInfo(g, "Tabname", Name) : NULL;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2013-10-27 10:37:12 +01:00
|
|
|
if (!Password)
|
2014-04-14 14:26:48 +02:00
|
|
|
Password = (b) ? GetStringCatInfo(g, "Password", NULL) : NULL;
|
2013-02-22 17:26:08 +01:00
|
|
|
} // endif URL
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (!share->port)
|
|
|
|
if (!share->hostname || strcmp(share->hostname, my_localhost) == 0)
|
|
|
|
share->socket= (char *) MYSQL_UNIX_ADDR;
|
|
|
|
else
|
|
|
|
share->port= MYSQL_PORT;
|
|
|
|
#endif // 0
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} // end of ParseURL
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* DefineAM: define specific AM block values from XCV file. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2013-06-16 19:07:27 +02:00
|
|
|
char *url;
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
Desc = "MySQL Table";
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2022-02-07 22:57:24 +01:00
|
|
|
Delayed = !!GetIntCatInfo("Delayed", 0);
|
|
|
|
Ignored = !!GetIntCatInfo("Ignored", 0);
|
|
|
|
|
2013-05-09 16:16:45 +02:00
|
|
|
if (stricmp(am, "MYPRX")) {
|
2013-05-02 16:33:15 +02:00
|
|
|
// Normal case of specific MYSQL table
|
2014-04-14 14:26:48 +02:00
|
|
|
url = GetStringCatInfo(g, "Connect", NULL);
|
2013-06-16 19:07:27 +02:00
|
|
|
|
2014-03-22 08:57:32 +01:00
|
|
|
if (!url || !*url) {
|
2013-05-02 16:33:15 +02:00
|
|
|
// Not using the connection URL
|
2014-04-14 14:26:48 +02:00
|
|
|
Hostname = GetStringCatInfo(g, "Host", "localhost");
|
2017-02-16 18:01:48 +01:00
|
|
|
Tabschema = GetStringCatInfo(g, "Database", "*");
|
2014-04-14 14:26:48 +02:00
|
|
|
Tabname = GetStringCatInfo(g, "Name", Name); // Deprecated
|
|
|
|
Tabname = GetStringCatInfo(g, "Tabname", Tabname);
|
|
|
|
Username = GetStringCatInfo(g, "User", "*");
|
|
|
|
Password = GetStringCatInfo(g, "Password", NULL);
|
|
|
|
Portnumber = GetIntCatInfo("Port", GetDefaultPort());
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = Hostname;
|
2013-05-02 16:33:15 +02:00
|
|
|
} else if (ParseURL(g, url))
|
2013-11-11 18:30:36 +01:00
|
|
|
return true;
|
2013-04-30 16:16:32 +02:00
|
|
|
|
2014-04-14 14:26:48 +02:00
|
|
|
Bind = !!GetIntCatInfo("Bind", 0);
|
2013-05-02 16:33:15 +02:00
|
|
|
} else {
|
2013-06-16 19:07:27 +02:00
|
|
|
// MYSQL access from a PROXY table
|
2019-11-16 14:59:54 +01:00
|
|
|
TABLE_SHARE* s;
|
|
|
|
|
|
|
|
Tabschema = GetStringCatInfo(g, "Database", Tabschema ? Tabschema : PlugDup(g, "*"));
|
2014-04-27 19:18:20 +02:00
|
|
|
Isview = GetBoolCatInfo("View", false);
|
2013-05-02 16:33:15 +02:00
|
|
|
|
2013-06-16 19:07:27 +02:00
|
|
|
// We must get other connection parms from the calling table
|
2019-11-16 14:59:54 +01:00
|
|
|
s = Remove_tshp(Cat);
|
2014-04-14 14:26:48 +02:00
|
|
|
url = GetStringCatInfo(g, "Connect", NULL);
|
2013-06-16 19:07:27 +02:00
|
|
|
|
|
|
|
if (!url || !*url) {
|
2014-04-14 14:26:48 +02:00
|
|
|
Hostname = GetStringCatInfo(g, "Host", "localhost");
|
|
|
|
Username = GetStringCatInfo(g, "User", "*");
|
|
|
|
Password = GetStringCatInfo(g, "Password", NULL);
|
|
|
|
Portnumber = GetIntCatInfo("Port", GetDefaultPort());
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = Hostname;
|
2013-06-16 19:07:27 +02:00
|
|
|
} else {
|
2017-05-11 21:57:21 +02:00
|
|
|
PCSZ locdb = Tabschema;
|
2013-06-16 19:07:27 +02:00
|
|
|
|
|
|
|
if (ParseURL(g, url))
|
2013-11-11 18:30:36 +01:00
|
|
|
return true;
|
2013-06-16 19:07:27 +02:00
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
Tabschema = locdb;
|
2013-06-16 19:07:27 +02:00
|
|
|
} // endif url
|
|
|
|
|
|
|
|
Tabname = Name;
|
2019-11-16 14:59:54 +01:00
|
|
|
|
|
|
|
// Needed for column description
|
|
|
|
Restore_tshp(Cat, s);
|
2013-05-02 16:33:15 +02:00
|
|
|
} // endif am
|
2013-02-22 17:26:08 +01:00
|
|
|
|
2014-07-17 18:13:51 +02:00
|
|
|
if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) {
|
|
|
|
Read_Only = true;
|
2013-11-11 18:30:36 +01:00
|
|
|
Isview = true;
|
2017-02-16 18:01:48 +01:00
|
|
|
} else if (CheckSelf(g, Hc->GetTable()->s, Hostname, Tabschema,
|
2014-07-17 18:13:51 +02:00
|
|
|
Tabname, Srcdef, Portnumber))
|
|
|
|
return true;
|
2013-11-11 18:30:36 +01:00
|
|
|
|
|
|
|
// Used for Update and Delete
|
2014-04-14 14:26:48 +02:00
|
|
|
Qrystr = GetStringCatInfo(g, "Query_String", "?");
|
|
|
|
Quoted = GetIntCatInfo("Quoted", 0);
|
2013-05-19 19:25:06 +02:00
|
|
|
|
2013-11-06 18:22:09 +01:00
|
|
|
// Specific for command executing tables
|
2014-04-14 14:26:48 +02:00
|
|
|
Xsrc = GetBoolCatInfo("Execsrc", false);
|
2017-02-16 18:01:48 +01:00
|
|
|
Maxerr = GetIntCatInfo("Maxerr", 0);
|
2014-04-27 19:18:20 +02:00
|
|
|
Huge = GetBoolCatInfo("Huge", false);
|
|
|
|
return false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of DefineAM
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* GetTable: makes a new TDB of the proper type. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2013-10-26 17:14:58 +02:00
|
|
|
if (Xsrc)
|
|
|
|
return new(g) TDBMYEXC(this);
|
|
|
|
else if (Catfunc == FNC_COL)
|
2013-02-11 00:31:03 +01:00
|
|
|
return new(g) TDBMCL(this);
|
|
|
|
else
|
|
|
|
return new(g) TDBMYSQL(this);
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of GetTable
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Implementation of the TDBMYSQL class. */
|
|
|
|
/***********************************************************************/
|
2017-02-16 18:01:48 +01:00
|
|
|
TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBEXT(tdp)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
|
|
|
if (tdp) {
|
2013-08-09 18:02:47 +02:00
|
|
|
Host = tdp->Hostname;
|
2017-02-16 18:01:48 +01:00
|
|
|
// Schema = tdp->Tabschema;
|
|
|
|
// TableName = tdp->Tabname;
|
|
|
|
// Srcdef = tdp->Srcdef;
|
|
|
|
// User = tdp->Username;
|
|
|
|
// Pwd = tdp->Password;
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = tdp->Server;
|
2017-02-16 18:01:48 +01:00
|
|
|
// Qrystr = tdp->Qrystr;
|
2014-04-21 12:57:10 +02:00
|
|
|
Quoted = MY_MAX(0, tdp->Quoted);
|
2013-08-09 18:02:47 +02:00
|
|
|
Port = tdp->Portnumber;
|
2013-05-19 19:25:06 +02:00
|
|
|
Isview = tdp->Isview;
|
2013-02-07 10:34:27 +01:00
|
|
|
Prep = tdp->Bind;
|
|
|
|
Delayed = tdp->Delayed;
|
2022-02-07 22:57:24 +01:00
|
|
|
Ignored = tdp->Ignored;
|
2014-04-27 19:18:20 +02:00
|
|
|
Myc.m_Use = tdp->Huge;
|
2013-02-07 10:34:27 +01:00
|
|
|
} else {
|
|
|
|
Host = NULL;
|
2017-02-16 18:01:48 +01:00
|
|
|
// Schema = NULL;
|
|
|
|
// TableName = NULL;
|
|
|
|
// Srcdef = NULL;
|
|
|
|
// User = NULL;
|
|
|
|
// Pwd = NULL;
|
2013-08-09 18:02:47 +02:00
|
|
|
Server = NULL;
|
2017-02-16 18:01:48 +01:00
|
|
|
// Qrystr = NULL;
|
|
|
|
// Quoted = 0;
|
2013-02-07 10:34:27 +01:00
|
|
|
Port = 0;
|
2014-04-27 19:18:20 +02:00
|
|
|
Isview = false;
|
|
|
|
Prep = false;
|
|
|
|
Delayed = false;
|
2022-02-07 22:57:24 +01:00
|
|
|
Ignored = false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif tdp
|
|
|
|
|
|
|
|
Bind = NULL;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Query = NULL;
|
2014-04-27 19:18:20 +02:00
|
|
|
Fetched = false;
|
2013-02-07 10:34:27 +01:00
|
|
|
m_Rc = RC_FX;
|
2017-02-16 18:01:48 +01:00
|
|
|
//AftRows = 0;
|
2013-02-07 10:34:27 +01:00
|
|
|
N = -1;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Nparm = 0;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of TDBMYSQL constructor
|
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
TDBMYSQL::TDBMYSQL(PTDBMY tdbp) : TDBEXT(tdbp)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
|
|
|
Host = tdbp->Host;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Schema = tdbp->Schema;
|
|
|
|
//TableName = tdbp->TableName;
|
|
|
|
//Srcdef = tdbp->Srcdef;
|
|
|
|
//User = tdbp->User;
|
|
|
|
//Pwd = tdbp->Pwd;
|
|
|
|
//Qrystr = tdbp->Qrystr;
|
|
|
|
//Quoted = tdbp->Quoted;
|
|
|
|
Server = tdbp->Server;
|
2013-02-07 10:34:27 +01:00
|
|
|
Port = tdbp->Port;
|
2013-05-19 19:25:06 +02:00
|
|
|
Isview = tdbp->Isview;
|
2013-02-07 10:34:27 +01:00
|
|
|
Prep = tdbp->Prep;
|
|
|
|
Delayed = tdbp->Delayed;
|
2022-02-07 22:57:24 +01:00
|
|
|
Ignored = tdbp->Ignored;
|
2013-02-07 10:34:27 +01:00
|
|
|
Bind = NULL;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Query = tdbp->Query;
|
2013-02-07 10:34:27 +01:00
|
|
|
Fetched = tdbp->Fetched;
|
|
|
|
m_Rc = tdbp->m_Rc;
|
2017-02-16 18:01:48 +01:00
|
|
|
//AftRows = tdbp->AftRows;
|
2013-02-07 10:34:27 +01:00
|
|
|
N = tdbp->N;
|
2017-02-16 18:01:48 +01:00
|
|
|
//Nparm = tdbp->Nparm;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of TDBMYSQL copy constructor
|
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
// Is this really useful ??? --> Yes for UPDATE
|
|
|
|
PTDB TDBMYSQL::Clone(PTABS t)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
|
|
|
PTDB tp;
|
|
|
|
PCOL cp1, cp2;
|
|
|
|
PGLOBAL g = t->G;
|
|
|
|
|
2015-05-09 17:30:20 +02:00
|
|
|
tp = new(g) TDBMYSQL(this);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
|
|
|
|
cp2 = new(g) MYSQLCOL((PMYCOL)cp1, tp);
|
|
|
|
|
|
|
|
NewPointer(t, cp1, cp2);
|
|
|
|
} // endfor cp1
|
|
|
|
|
|
|
|
return tp;
|
2017-02-16 18:01:48 +01:00
|
|
|
} // end of Clone
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Allocate MYSQL column description block. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
|
|
{
|
|
|
|
return new(g) MYSQLCOL(cdp, this, cprec, n);
|
|
|
|
} // end of MakeCol
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MakeSelect: make the Select statement use with MySQL connection. */
|
|
|
|
/* Note: when implementing EOM filtering, column only used in local */
|
|
|
|
/* filter should be removed from column list. */
|
|
|
|
/***********************************************************************/
|
2014-04-19 17:02:53 +02:00
|
|
|
bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx)
|
2017-05-11 21:57:21 +02:00
|
|
|
{
|
2014-10-21 17:29:51 +02:00
|
|
|
//char *tk = "`";
|
|
|
|
char tk = '`';
|
2014-04-19 17:02:53 +02:00
|
|
|
int len = 0, rank = 0;
|
2017-05-11 21:57:21 +02:00
|
|
|
bool b = false;
|
2013-02-07 10:34:27 +01:00
|
|
|
PCOL colp;
|
2013-05-19 19:25:06 +02:00
|
|
|
//PDBUSER dup = PlgGetUser(g);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
if (Query)
|
2014-04-19 17:02:53 +02:00
|
|
|
return false; // already done
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-09-19 01:04:05 +02:00
|
|
|
if (Srcdef)
|
|
|
|
return MakeSrcdef(g);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
// Allocate the string used to contain Query
|
|
|
|
Query = new(g) STRING(g, 1023, "SELECT ");
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
if (Columns) {
|
2013-02-07 10:34:27 +01:00
|
|
|
for (colp = Columns; colp; colp = colp->GetNext())
|
2013-08-09 18:02:47 +02:00
|
|
|
if (!colp->IsSpecial()) {
|
2013-02-07 10:34:27 +01:00
|
|
|
if (b)
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(", ");
|
2013-02-07 10:34:27 +01:00
|
|
|
else
|
2014-04-19 17:02:53 +02:00
|
|
|
b = true;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(tk);
|
|
|
|
Query->Append(colp->GetName());
|
|
|
|
Query->Append(tk);
|
2013-02-07 10:34:27 +01:00
|
|
|
((PMYCOL)colp)->Rank = rank++;
|
|
|
|
} // endif colp
|
|
|
|
|
|
|
|
} else {
|
2013-05-19 19:25:06 +02:00
|
|
|
// ncol == 0 can occur for views or queries such as
|
|
|
|
// Query count(*) from... for which we will count the rows from
|
|
|
|
// Query '*' from...
|
2013-02-07 10:34:27 +01:00
|
|
|
// (the use of a char constant minimize the result storage)
|
2014-10-21 17:29:51 +02:00
|
|
|
if (Isview)
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append('*');
|
2014-10-21 17:29:51 +02:00
|
|
|
else
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append("'*'");
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif ncol
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(" FROM ");
|
|
|
|
Query->Append(tk);
|
|
|
|
Query->Append(TableName);
|
|
|
|
Query->Append(tk);
|
2014-10-21 17:29:51 +02:00
|
|
|
len = Query->GetLength();
|
2014-04-19 17:02:53 +02:00
|
|
|
|
|
|
|
if (To_CondFil) {
|
|
|
|
if (!mx) {
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(" WHERE ");
|
|
|
|
Query->Append(To_CondFil->Body);
|
2014-10-21 17:29:51 +02:00
|
|
|
len = Query->GetLength() + 1;
|
2014-04-19 17:02:53 +02:00
|
|
|
} else
|
|
|
|
len += (strlen(To_CondFil->Body) + 256);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-04-19 17:02:53 +02:00
|
|
|
} else
|
|
|
|
len += (mx ? 256 : 1);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if (Query->IsTruncated() || Query->Resize(len)) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "MakeSelect: Out of memory");
|
2014-10-21 17:29:51 +02:00
|
|
|
return true;
|
2017-05-11 21:57:21 +02:00
|
|
|
} // endif Query
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(33))
|
2014-10-21 17:29:51 +02:00
|
|
|
htrc("Query=%s\n", Query->GetStr());
|
2013-10-02 19:58:49 +02:00
|
|
|
|
2014-04-19 17:02:53 +02:00
|
|
|
return false;
|
2017-05-11 21:57:21 +02:00
|
|
|
} // end of MakeSelect
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MakeInsert: make the Insert statement used with MySQL connection. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool TDBMYSQL::MakeInsert(PGLOBAL g)
|
|
|
|
{
|
2017-05-11 21:57:21 +02:00
|
|
|
const char *tk = "`";
|
2014-10-21 17:29:51 +02:00
|
|
|
uint len = 0;
|
2017-05-11 21:57:21 +02:00
|
|
|
bool oom, b = false;
|
2013-02-07 10:34:27 +01:00
|
|
|
PCOL colp;
|
|
|
|
|
|
|
|
if (Query)
|
2014-04-27 19:18:20 +02:00
|
|
|
return false; // already done
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
if (Prep) {
|
2014-10-21 17:29:51 +02:00
|
|
|
#if !defined(MYSQL_PREPARED_STATEMENTS)
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Prepared statements not used (not supported)");
|
2013-02-20 16:57:38 +01:00
|
|
|
PushWarning(g, this);
|
2014-04-27 19:18:20 +02:00
|
|
|
Prep = false;
|
2013-02-20 16:57:38 +01:00
|
|
|
#endif // !MYSQL_PREPARED_STATEMENTS
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif Prep
|
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
for (colp = Columns; colp; colp = colp->GetNext())
|
|
|
|
if (colp->IsSpecial()) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(NO_SPEC_COL));
|
2014-10-21 17:29:51 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
len += (strlen(colp->GetName()) + 4);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
// Parameter marker
|
|
|
|
if (!Prep) {
|
|
|
|
if (colp->GetResultType() == TYPE_DATE)
|
|
|
|
len += 20;
|
|
|
|
else
|
|
|
|
len += colp->GetLength();
|
|
|
|
|
|
|
|
} else
|
|
|
|
len += 2;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
((PMYCOL)colp)->Rank = Nparm++;
|
|
|
|
} // endif colp
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
// Below 40 is enough to contain the fixed part of the query
|
2017-02-16 18:01:48 +01:00
|
|
|
len += (strlen(TableName) + 40);
|
2014-10-21 17:29:51 +02:00
|
|
|
Query = new(g) STRING(g, len);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2022-02-07 22:57:24 +01:00
|
|
|
Query->Set("INSERT ");
|
2013-02-07 10:34:27 +01:00
|
|
|
if (Delayed)
|
2022-02-07 22:57:24 +01:00
|
|
|
Query->Append("DELAYED ");
|
|
|
|
if (Ignored)
|
|
|
|
Query->Append("IGNORE ");
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2022-02-07 22:57:24 +01:00
|
|
|
Query->Append("INTO ");
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(tk);
|
|
|
|
Query->Append(TableName);
|
|
|
|
Query->Append("` (");
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
for (colp = Columns; colp; colp = colp->GetNext()) {
|
|
|
|
if (b)
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(", ");
|
2014-10-21 17:29:51 +02:00
|
|
|
else
|
|
|
|
b = true;
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(tk);
|
|
|
|
Query->Append(colp->GetName());
|
|
|
|
Query->Append(tk);
|
2014-10-21 17:29:51 +02:00
|
|
|
} // endfor colp
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(") VALUES (");
|
2014-10-21 17:29:51 +02:00
|
|
|
|
|
|
|
#if defined(MYSQL_PREPARED_STATEMENTS)
|
|
|
|
if (Prep) {
|
|
|
|
for (int i = 0; i < Nparm; i++)
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append("?,");
|
2014-10-21 17:29:51 +02:00
|
|
|
|
|
|
|
Query->RepLast(')');
|
|
|
|
Query->Trim();
|
|
|
|
} // endif Prep
|
|
|
|
#endif // MYSQL_PREPARED_STATEMENTS
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((oom = Query->IsTruncated()))
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "MakeInsert: Out of memory");
|
2014-10-21 17:29:51 +02:00
|
|
|
|
|
|
|
return oom;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of MakeInsert
|
|
|
|
|
2013-11-13 00:15:38 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* MakeCommand: make the Update or Delete statement to send to the */
|
|
|
|
/* MySQL server. Limited to remote values and filtering. */
|
|
|
|
/***********************************************************************/
|
2017-02-16 18:01:48 +01:00
|
|
|
bool TDBMYSQL::MakeCommand(PGLOBAL g)
|
2013-11-13 00:15:38 +01:00
|
|
|
{
|
2014-10-21 17:29:51 +02:00
|
|
|
Query = new(g) STRING(g, strlen(Qrystr) + 64);
|
2013-11-13 00:15:38 +01:00
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
if (Quoted > 0 || stricmp(Name, TableName)) {
|
2013-11-13 00:15:38 +01:00
|
|
|
char *p, *qrystr, name[68];
|
|
|
|
bool qtd = Quoted > 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Make a lower case copy of the originale query
|
2014-07-22 15:51:21 +02:00
|
|
|
qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 5);
|
2013-11-13 00:15:38 +01:00
|
|
|
strlwr(strcpy(qrystr, Qrystr));
|
|
|
|
|
|
|
|
// Check whether the table name is equal to a keyword
|
|
|
|
// If so, it must be quoted in the original query
|
|
|
|
strlwr(strcat(strcat(strcpy(name, "`"), Name), "`"));
|
|
|
|
|
|
|
|
if (!strstr("`update`delete`low_priority`ignore`quick`from`", name))
|
|
|
|
strlwr(strcpy(name, Name)); // Not a keyword
|
|
|
|
|
|
|
|
if ((p = strstr(qrystr, name))) {
|
2018-04-24 20:28:31 +02:00
|
|
|
Query->Set(Qrystr, (uint)(p - qrystr));
|
2013-11-13 00:15:38 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
if (qtd && *(p-1) == ' ') {
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append('`');
|
|
|
|
Query->Append(TableName);
|
|
|
|
Query->Append('`');
|
2014-10-21 17:29:51 +02:00
|
|
|
} else
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(TableName);
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(Qrystr + (p - qrystr) + strlen(name));
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if (Query->IsTruncated()) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "MakeCommand: Out of memory");
|
2017-02-16 18:01:48 +01:00
|
|
|
return true;
|
2014-10-21 17:29:51 +02:00
|
|
|
} else
|
|
|
|
strlwr(strcpy(qrystr, Query->GetStr()));
|
2013-11-13 00:15:38 +01:00
|
|
|
|
|
|
|
} else {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Cannot use this %s command",
|
2013-11-13 00:15:38 +01:00
|
|
|
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
|
2017-02-16 18:01:48 +01:00
|
|
|
return true;
|
2013-11-13 00:15:38 +01:00
|
|
|
} // endif p
|
|
|
|
|
|
|
|
} else
|
2014-10-21 17:29:51 +02:00
|
|
|
(void)Query->Set(Qrystr);
|
2013-11-13 00:15:38 +01:00
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
return false;
|
2013-11-13 00:15:38 +01:00
|
|
|
} // end of MakeCommand
|
|
|
|
|
|
|
|
#if 0
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* MakeUpdate: make the Update statement use with MySQL connection. */
|
2013-11-11 18:30:36 +01:00
|
|
|
/* Limited to remote values and filtering. */
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
2013-11-11 18:30:36 +01:00
|
|
|
int TDBMYSQL::MakeUpdate(PGLOBAL g)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2013-11-11 18:30:36 +01:00
|
|
|
char *qc, cmd[8], tab[96], end[1024];
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
|
|
|
|
memset(end, 0, sizeof(end));
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
|
|
|
|
sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
|
|
|
|
qc = "`";
|
2013-11-13 00:15:38 +01:00
|
|
|
else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2
|
|
|
|
&& !stricmp(tab, Name))
|
2013-11-11 18:30:36 +01:00
|
|
|
qc = (Quoted) ? "`" : "";
|
|
|
|
else {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Cannot use this UPDATE command");
|
2013-11-11 18:30:36 +01:00
|
|
|
return RC_FX;
|
|
|
|
} // endif sscanf
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
assert(!stricmp(cmd, "update"));
|
2017-02-16 18:01:48 +01:00
|
|
|
strcat(strcat(strcat(strcpy(Query, "UPDATE "), qc), TableName), qc);
|
2013-11-11 18:30:36 +01:00
|
|
|
strcat(Query, end);
|
|
|
|
return RC_OK;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of MakeUpdate
|
|
|
|
|
|
|
|
/***********************************************************************/
|
2013-11-11 18:30:36 +01:00
|
|
|
/* MakeDelete: make the Delete statement used with MySQL connection. */
|
|
|
|
/* Limited to remote filtering. */
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
2013-11-11 18:30:36 +01:00
|
|
|
int TDBMYSQL::MakeDelete(PGLOBAL g)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2013-11-11 18:30:36 +01:00
|
|
|
char *qc, cmd[8], from[8], tab[96], end[512];
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
|
|
|
|
memset(end, 0, sizeof(end));
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
|
|
|
|
sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
|
|
|
|
qc = "`";
|
|
|
|
else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
|
|
|
|
qc = (Quoted) ? "`" : "";
|
|
|
|
else {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Cannot use this DELETE command");
|
2013-11-11 18:30:36 +01:00
|
|
|
return RC_FX;
|
|
|
|
} // endif sscanf
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
|
2017-02-16 18:01:48 +01:00
|
|
|
strcat(strcat(strcat(strcpy(Query, "DELETE FROM "), qc), TableName), qc);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
if (*end)
|
|
|
|
strcat(Query, end);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
return RC_OK;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of MakeDelete
|
2013-11-13 00:15:38 +01:00
|
|
|
#endif // 0
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
/***********************************************************************/
|
2014-07-17 18:13:51 +02:00
|
|
|
/* MYSQL Cardinality: returns the number of rows in the table. */
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
2014-07-17 18:13:51 +02:00
|
|
|
int TDBMYSQL::Cardinality(PGLOBAL g)
|
|
|
|
{
|
|
|
|
if (!g)
|
|
|
|
return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
|
2014-07-17 18:13:51 +02:00
|
|
|
// Info command, we must return the exact table row number
|
|
|
|
char query[96];
|
|
|
|
MYSQLC myc;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
if (myc.Open(g, Host, Schema, User, Pwd, Port, csname))
|
2014-07-17 18:13:51 +02:00
|
|
|
return -1;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-07-17 18:13:51 +02:00
|
|
|
strcpy(query, "SELECT COUNT(*) FROM ");
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2014-07-17 18:13:51 +02:00
|
|
|
if (Quoted > 0)
|
2017-02-16 18:01:48 +01:00
|
|
|
strcat(strcat(strcat(query, "`"), TableName), "`");
|
2014-07-17 18:13:51 +02:00
|
|
|
else
|
2017-02-16 18:01:48 +01:00
|
|
|
strcat(query, TableName);
|
2014-07-17 18:13:51 +02:00
|
|
|
|
|
|
|
Cardinal = myc.GetTableSize(g, query);
|
|
|
|
myc.Close();
|
2014-08-07 17:59:21 +02:00
|
|
|
} else
|
|
|
|
Cardinal = 10; // To make MySQL happy
|
2014-07-17 18:13:51 +02:00
|
|
|
|
|
|
|
return Cardinal;
|
|
|
|
} // end of Cardinality
|
|
|
|
|
2017-02-16 18:01:48 +01:00
|
|
|
#if 0
|
2014-07-17 18:13:51 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* MYSQL GetMaxSize: returns the maximum number of rows in the table. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::GetMaxSize(PGLOBAL g)
|
|
|
|
{
|
|
|
|
if (MaxSize < 0) {
|
|
|
|
if (Mode == MODE_DELETE)
|
|
|
|
// Return 0 in mode DELETE in case of delete all.
|
|
|
|
MaxSize = 0;
|
|
|
|
else if (!Cardinality(NULL))
|
|
|
|
MaxSize = 10; // To make MySQL happy
|
|
|
|
else if ((MaxSize = Cardinality(g)) < 0)
|
2016-03-04 01:09:37 +01:00
|
|
|
MaxSize = 12; // So we can see an error occurred
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} // endif MaxSize
|
|
|
|
|
|
|
|
return MaxSize;
|
|
|
|
} // end of GetMaxSize
|
2017-02-16 18:01:48 +01:00
|
|
|
#endif // 0
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* This a fake routine as ROWID does not exist in MySQL. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
int TDBMYSQL::RowNumber(PGLOBAL, bool)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2014-10-21 17:29:51 +02:00
|
|
|
return N + 1;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of RowNumber
|
|
|
|
|
|
|
|
/***********************************************************************/
|
2013-11-11 18:30:36 +01:00
|
|
|
/* Return 0 in mode UPDATE to tell that the update is done. */
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::GetProgMax(PGLOBAL g)
|
|
|
|
{
|
2013-11-11 18:30:36 +01:00
|
|
|
return (Mode == MODE_UPDATE) ? 0 : GetMaxSize(g);
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of GetProgMax
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MySQL Bind Parameter function. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
int TDBMYSQL::BindColumns(PGLOBAL g __attribute__((unused)))
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
2013-02-20 16:57:38 +01:00
|
|
|
#if defined(MYSQL_PREPARED_STATEMENTS)
|
2013-02-07 10:34:27 +01:00
|
|
|
if (Prep) {
|
|
|
|
Bind = (MYSQL_BIND*)PlugSubAlloc(g, NULL, Nparm * sizeof(MYSQL_BIND));
|
|
|
|
|
|
|
|
for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
|
|
|
|
colp->InitBind(g);
|
|
|
|
|
|
|
|
return Myc.BindParams(g, Bind);
|
2013-02-20 16:57:38 +01:00
|
|
|
} // endif prep
|
|
|
|
#endif // MYSQL_PREPARED_STATEMENTS
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-02-20 16:57:38 +01:00
|
|
|
return RC_OK;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of BindColumns
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MySQL Access Method opening routine. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool TDBMYSQL::OpenDB(PGLOBAL g)
|
|
|
|
{
|
|
|
|
if (Use == USE_OPEN) {
|
|
|
|
/*******************************************************************/
|
|
|
|
/* Table already open, just replace it at its beginning. */
|
|
|
|
/*******************************************************************/
|
2016-04-25 00:13:06 +02:00
|
|
|
if (Myc.Rewind(g, (Mode == MODE_READX) ? Query->GetStr() : NULL) != RC_OK)
|
|
|
|
return true;
|
|
|
|
|
2014-11-15 18:28:24 +01:00
|
|
|
N = -1;
|
2013-05-19 19:25:06 +02:00
|
|
|
return false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif use
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Open a MySQL connection for this table. */
|
|
|
|
/* Note: this may not be the proper way to do. Perhaps it is better */
|
|
|
|
/* to test whether a connection is already open for this server */
|
|
|
|
/* and if so to allocate just a new result set. But this only for */
|
|
|
|
/* servers allowing concurency in getting results ??? */
|
|
|
|
/*********************************************************************/
|
|
|
|
if (!Myc.Connected()) {
|
2017-02-16 18:01:48 +01:00
|
|
|
if (Myc.Open(g, Host, Schema, User, Pwd, Port, csname))
|
2013-05-19 19:25:06 +02:00
|
|
|
return true;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} // endif Connected
|
|
|
|
|
2013-06-26 19:42:28 +02:00
|
|
|
/*********************************************************************/
|
|
|
|
/* Take care of DATE columns. */
|
|
|
|
/*********************************************************************/
|
|
|
|
for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
|
|
|
|
if (colp->Buf_Type == TYPE_DATE)
|
|
|
|
// Format must match DATETIME MySQL type
|
|
|
|
((DTVAL*)colp->GetValue())->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/*********************************************************************/
|
|
|
|
/* Allocate whatever is used for getting results. */
|
|
|
|
/*********************************************************************/
|
2014-04-19 17:02:53 +02:00
|
|
|
if (Mode == MODE_READ || Mode == MODE_READX) {
|
|
|
|
MakeSelect(g, Mode == MODE_READX);
|
2022-01-25 10:34:13 +01:00
|
|
|
if (Mode == MODE_READ && !Query)
|
|
|
|
{
|
|
|
|
Myc.Close();
|
|
|
|
return true;
|
|
|
|
}
|
2014-10-21 17:29:51 +02:00
|
|
|
m_Rc = (Mode == MODE_READ)
|
|
|
|
? Myc.ExecSQL(g, Query->GetStr()) : RC_OK;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
#if 0
|
|
|
|
if (!Myc.m_Res || !Myc.m_Fields) {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "%s result", (Myc.m_Res) ? "Void" : "No");
|
2013-05-19 19:25:06 +02:00
|
|
|
Myc.Close();
|
|
|
|
return true;
|
|
|
|
} // endif m_Res
|
|
|
|
#endif // 0
|
|
|
|
|
2013-05-24 00:19:26 +02:00
|
|
|
if (!m_Rc && Srcdef)
|
2013-05-19 19:25:06 +02:00
|
|
|
if (SetColumnRanks(g))
|
|
|
|
return true;
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
} else if (Mode == MODE_INSERT) {
|
2013-05-19 19:25:06 +02:00
|
|
|
if (Srcdef) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "No insert into anonym views");
|
2014-09-30 12:59:24 +02:00
|
|
|
Myc.Close();
|
2013-05-19 19:25:06 +02:00
|
|
|
return true;
|
|
|
|
} // endif Srcdef
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
if (!MakeInsert(g)) {
|
2013-02-20 16:57:38 +01:00
|
|
|
#if defined(MYSQL_PREPARED_STATEMENTS)
|
2014-10-21 17:29:51 +02:00
|
|
|
int n = (Prep)
|
|
|
|
? Myc.PrepareSQL(g, Query->GetCharValue()) : Nparm;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
if (Nparm != n) {
|
|
|
|
if (n >= 0) // Other errors return negative values
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(BAD_PARM_COUNT));
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} else
|
2013-02-20 16:57:38 +01:00
|
|
|
#endif // MYSQL_PREPARED_STATEMENTS
|
2013-02-07 10:34:27 +01:00
|
|
|
m_Rc = BindColumns(g);
|
|
|
|
|
|
|
|
} // endif MakeInsert
|
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
} else
|
2013-11-13 00:15:38 +01:00
|
|
|
// m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g);
|
2017-02-16 18:01:48 +01:00
|
|
|
m_Rc = (MakeCommand(g)) ? RC_FX : RC_OK;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
if (m_Rc == RC_FX) {
|
|
|
|
Myc.Close();
|
2013-11-11 18:30:36 +01:00
|
|
|
return true;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif rc
|
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
Use = USE_OPEN;
|
|
|
|
return false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of OpenDB
|
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Set the rank of columns in the result set. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool TDBMYSQL::SetColumnRanks(PGLOBAL g)
|
|
|
|
{
|
|
|
|
for (PCOL colp = Columns; colp; colp = colp->GetNext())
|
|
|
|
if (((PMYCOL)colp)->FindRank(g))
|
2014-04-27 19:18:20 +02:00
|
|
|
return true;
|
2013-05-19 19:25:06 +02:00
|
|
|
|
2014-04-27 19:18:20 +02:00
|
|
|
return false;
|
2013-05-19 19:25:06 +02:00
|
|
|
} // end of SetColumnRanks
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Called by Parent table to make the columns of a View. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PCOL TDBMYSQL::MakeFieldColumn(PGLOBAL g, char *name)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
MYSQL_FIELD *fld;
|
|
|
|
PCOL cp, colp = NULL;
|
|
|
|
|
|
|
|
for (n = 0; n < Myc.m_Fields; n++) {
|
|
|
|
fld = &Myc.m_Res->fields[n];
|
|
|
|
|
|
|
|
if (!stricmp(name, fld->name)) {
|
|
|
|
colp = new(g) MYSQLCOL(fld, this, n);
|
|
|
|
|
|
|
|
if (colp->InitValue(g))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!Columns)
|
|
|
|
Columns = colp;
|
|
|
|
else for (cp = Columns; cp; cp = cp->GetNext())
|
|
|
|
if (!cp->GetNext()) {
|
|
|
|
cp->SetNext(colp);
|
|
|
|
break;
|
|
|
|
} // endif Next
|
|
|
|
|
|
|
|
break;
|
|
|
|
} // endif name
|
|
|
|
|
|
|
|
} // endfor n
|
|
|
|
|
|
|
|
if (!colp)
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Column %s is not in view", name);
|
2013-05-19 19:25:06 +02:00
|
|
|
|
|
|
|
return colp;
|
|
|
|
} // end of MakeFieldColumn
|
|
|
|
|
2013-05-22 13:35:21 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Called by Pivot tables to find default column names in a View */
|
|
|
|
/* as the name of last field not equal to the passed name. */
|
|
|
|
/***********************************************************************/
|
|
|
|
char *TDBMYSQL::FindFieldColumn(char *name)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
MYSQL_FIELD *fld;
|
|
|
|
char *cp = NULL;
|
|
|
|
|
|
|
|
for (n = Myc.m_Fields - 1; n >= 0; n--) {
|
|
|
|
fld = &Myc.m_Res->fields[n];
|
|
|
|
|
|
|
|
if (!name || stricmp(name, fld->name)) {
|
|
|
|
cp = fld->name;
|
|
|
|
break;
|
|
|
|
} // endif name
|
|
|
|
|
|
|
|
} // endfor n
|
|
|
|
|
|
|
|
return cp;
|
|
|
|
} // end of FindFieldColumn
|
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Send an UPDATE or DELETE command to the remote server. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::SendCommand(PGLOBAL g)
|
|
|
|
{
|
|
|
|
int w;
|
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
if (Myc.ExecSQLcmd(g, Query->GetStr(), &w) == RC_NF) {
|
2013-11-11 18:30:36 +01:00
|
|
|
AftRows = Myc.m_Afrw;
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "%s: %d affected rows", TableName, AftRows);
|
2013-11-11 18:30:36 +01:00
|
|
|
PushWarning(g, this, 0); // 0 means a Note
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2013-11-11 18:30:36 +01:00
|
|
|
htrc("%s\n", g->Message);
|
|
|
|
|
|
|
|
if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) {
|
|
|
|
// We got warnings from the remote server
|
|
|
|
while (Myc.Fetch(g, -1) == RC_OK) {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "%s: (%s) %s", TableName,
|
2013-11-11 18:30:36 +01:00
|
|
|
Myc.GetCharField(1), Myc.GetCharField(2));
|
|
|
|
PushWarning(g, this);
|
|
|
|
} // endwhile Fetch
|
|
|
|
|
|
|
|
Myc.FreeResult();
|
|
|
|
} // endif w
|
|
|
|
|
|
|
|
return RC_EF; // Nothing else to do
|
|
|
|
} else
|
|
|
|
return RC_FX; // Error
|
|
|
|
|
|
|
|
} // end of SendCommand
|
|
|
|
|
2014-04-19 17:02:53 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Data Base indexed read routine for MYSQL access method. */
|
|
|
|
/***********************************************************************/
|
2015-12-04 22:38:16 +01:00
|
|
|
bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
|
2014-04-19 17:02:53 +02:00
|
|
|
{
|
2014-10-21 17:29:51 +02:00
|
|
|
int oldlen = Query->GetLength();
|
2015-07-07 15:55:32 +02:00
|
|
|
PHC hc = To_Def->GetHandler();
|
2014-04-19 17:02:53 +02:00
|
|
|
|
2015-12-04 22:38:16 +01:00
|
|
|
if (!(kr || hc->end_range) || op == OP_NEXT ||
|
|
|
|
Mode == MODE_UPDATE || Mode == MODE_DELETE) {
|
|
|
|
if (!kr && Mode == MODE_READX) {
|
2015-05-02 15:36:33 +02:00
|
|
|
// This is a false indexed read
|
|
|
|
m_Rc = Myc.ExecSQL(g, Query->GetStr());
|
|
|
|
Mode = MODE_READ;
|
|
|
|
return (m_Rc == RC_FX) ? true : false;
|
|
|
|
} // endif key
|
|
|
|
|
2014-04-19 17:02:53 +02:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (Myc.m_Res)
|
|
|
|
Myc.FreeResult();
|
|
|
|
|
2015-12-04 22:38:16 +01:00
|
|
|
if (hc->MakeKeyWhere(g, Query, op, '`', kr))
|
2015-07-07 15:55:32 +02:00
|
|
|
return true;
|
2014-04-19 17:02:53 +02:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
if (To_CondFil) {
|
2015-12-04 22:38:16 +01:00
|
|
|
if (To_CondFil->Idx != hc->active_index) {
|
|
|
|
To_CondFil->Idx = hc->active_index;
|
|
|
|
To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
|
|
|
|
*To_CondFil->Body= 0;
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
|
2015-12-04 22:38:16 +01:00
|
|
|
PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
|
|
|
|
|
|
|
|
} // endif active_index
|
|
|
|
|
|
|
|
if (To_CondFil)
|
|
|
|
if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Readkey: Out of memory");
|
2015-12-04 22:38:16 +01:00
|
|
|
return true;
|
|
|
|
} // endif Append
|
|
|
|
|
|
|
|
} // endif To_Condfil
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2015-12-04 22:38:16 +01:00
|
|
|
Mode = MODE_READ;
|
|
|
|
} // endif's op
|
2014-04-19 17:02:53 +02:00
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(33))
|
2015-12-04 22:38:16 +01:00
|
|
|
htrc("MYSQL ReadKey: Query=%s\n", Query->GetStr());
|
2014-04-19 17:02:53 +02:00
|
|
|
|
2015-12-04 22:38:16 +01:00
|
|
|
m_Rc = Myc.ExecSQL(g, Query->GetStr());
|
2014-10-21 17:29:51 +02:00
|
|
|
Query->Truncate(oldlen);
|
2014-07-22 15:51:21 +02:00
|
|
|
return (m_Rc == RC_FX) ? true : false;
|
2014-04-19 17:02:53 +02:00
|
|
|
} // end of ReadKey
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* Data Base read routine for MYSQL access method. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::ReadDB(PGLOBAL g)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(2))
|
2017-02-16 18:01:48 +01:00
|
|
|
htrc("MySQL ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-11-11 18:30:36 +01:00
|
|
|
if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
|
|
|
|
return SendCommand(g);
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/*********************************************************************/
|
|
|
|
/* Now start the reading process. */
|
|
|
|
/* Here is the place to fetch the line. */
|
|
|
|
/*********************************************************************/
|
|
|
|
N++;
|
|
|
|
Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK);
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(2))
|
2013-02-07 10:34:27 +01:00
|
|
|
htrc(" Read: rc=%d\n", rc);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
} // end of ReadDB
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* WriteDB: Data Base write routine for MYSQL access methods. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::WriteDB(PGLOBAL g)
|
|
|
|
{
|
2013-02-20 16:57:38 +01:00
|
|
|
#if defined(MYSQL_PREPARED_STATEMENTS)
|
2013-02-07 10:34:27 +01:00
|
|
|
if (Prep)
|
|
|
|
return Myc.ExecStmt(g);
|
2013-02-20 16:57:38 +01:00
|
|
|
#endif // MYSQL_PREPARED_STATEMENTS
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
// Statement was not prepared, we must construct and execute
|
|
|
|
// an insert query for each line to insert
|
|
|
|
int rc;
|
2014-10-21 17:29:51 +02:00
|
|
|
uint len = Query->GetLength();
|
2014-03-18 19:25:50 +01:00
|
|
|
char buf[64];
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
// Make the Insert command value list
|
|
|
|
for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
|
2013-02-25 22:44:42 +01:00
|
|
|
if (!colp->GetValue()->IsNull()) {
|
2015-01-23 17:54:53 +01:00
|
|
|
if (colp->GetResultType() == TYPE_STRING ||
|
|
|
|
colp->GetResultType() == TYPE_DATE)
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append_quoted(colp->GetValue()->GetCharString(buf));
|
2015-01-23 17:54:53 +01:00
|
|
|
else
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(colp->GetValue()->GetCharString(buf));
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2013-02-25 22:44:42 +01:00
|
|
|
} else
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append("NULL");
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
Query->Append(',');
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endfor colp
|
|
|
|
|
2017-05-11 21:57:21 +02:00
|
|
|
if (unlikely(Query->IsTruncated())) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "WriteDB: Out of memory");
|
2014-10-21 17:29:51 +02:00
|
|
|
rc = RC_FX;
|
|
|
|
} else {
|
|
|
|
Query->RepLast(')');
|
|
|
|
Myc.m_Rows = -1; // To execute the query
|
|
|
|
rc = Myc.ExecSQL(g, Query->GetStr());
|
|
|
|
Query->Truncate(len); // Restore query
|
2017-05-11 21:57:21 +02:00
|
|
|
} // endif Query
|
2014-10-21 17:29:51 +02:00
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok
|
|
|
|
} // end of WriteDB
|
|
|
|
|
|
|
|
/***********************************************************************/
|
2013-11-11 18:30:36 +01:00
|
|
|
/* Data Base delete all routine for MYSQL access methods. */
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
|
|
|
|
{
|
2013-11-11 18:30:36 +01:00
|
|
|
if (irc == RC_FX)
|
|
|
|
// Send the DELETE (all) command to the remote table
|
2014-03-22 08:57:32 +01:00
|
|
|
return (SendCommand(g) == RC_FX) ? RC_FX : RC_OK;
|
2013-11-11 18:30:36 +01:00
|
|
|
else
|
|
|
|
return RC_OK; // Ignore
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of DeleteDB
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Data Base close routine for MySQL access method. */
|
|
|
|
/***********************************************************************/
|
|
|
|
void TDBMYSQL::CloseDB(PGLOBAL g)
|
|
|
|
{
|
2013-10-11 13:57:56 +02:00
|
|
|
if (Myc.Connected()) {
|
|
|
|
|
|
|
|
Myc.Close();
|
|
|
|
} // endif Myc
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2013-02-07 10:34:27 +01:00
|
|
|
htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
|
|
|
|
|
|
|
|
} // end of CloseDB
|
|
|
|
|
|
|
|
// ------------------------ MYSQLCOL functions --------------------------
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MYSQLCOL public constructor. */
|
|
|
|
/***********************************************************************/
|
2017-05-11 21:57:21 +02:00
|
|
|
MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
|
2013-02-07 10:34:27 +01:00
|
|
|
: COLBLK(cdp, tdbp, i)
|
|
|
|
{
|
|
|
|
if (cprec) {
|
|
|
|
Next = cprec->GetNext();
|
|
|
|
cprec->SetNext(this);
|
|
|
|
} else {
|
|
|
|
Next = tdbp->GetColumns();
|
|
|
|
tdbp->SetColumns(this);
|
|
|
|
} // endif cprec
|
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
// Set additional MySQL access method information for column.
|
2013-12-28 15:46:49 +01:00
|
|
|
Precision = Long = cdp->GetLong();
|
2013-02-07 10:34:27 +01:00
|
|
|
Bind = NULL;
|
|
|
|
To_Val = NULL;
|
|
|
|
Slen = 0;
|
|
|
|
Rank = -1; // Not known yet
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2013-02-07 10:34:27 +01:00
|
|
|
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
|
|
|
|
|
|
|
|
} // end of MYSQLCOL constructor
|
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* MYSQLCOL public constructor. */
|
|
|
|
/***********************************************************************/
|
2017-05-11 21:57:21 +02:00
|
|
|
MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
|
2013-05-19 19:25:06 +02:00
|
|
|
: COLBLK(NULL, tdbp, i)
|
|
|
|
{
|
2019-04-19 12:15:46 +02:00
|
|
|
//const char *chset = get_charset_name(fld->charsetnr);
|
2017-09-19 01:04:05 +02:00
|
|
|
//char v = (!strcmp(chset, "binary")) ? 'B' : 0;
|
|
|
|
char v = 0;
|
2014-03-30 22:52:54 +02:00
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
Name = fld->name;
|
2014-03-22 08:57:32 +01:00
|
|
|
Opt = 0;
|
2013-12-28 15:46:49 +01:00
|
|
|
Precision = Long = fld->length;
|
2014-03-30 22:52:54 +02:00
|
|
|
Buf_Type = MYSQLtoPLG(fld->type, &v);
|
2013-05-19 19:25:06 +02:00
|
|
|
strcpy(Format.Type, GetFormatType(Buf_Type));
|
|
|
|
Format.Length = Long;
|
|
|
|
Format.Prec = fld->decimals;
|
|
|
|
ColUse = U_P;
|
|
|
|
Nullable = !IS_NOT_NULL(fld->flags);
|
|
|
|
|
|
|
|
// Set additional MySQL access method information for column.
|
|
|
|
Bind = NULL;
|
|
|
|
To_Val = NULL;
|
|
|
|
Slen = 0;
|
|
|
|
Rank = i;
|
|
|
|
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2013-05-19 19:25:06 +02:00
|
|
|
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
|
|
|
|
|
|
|
|
} // end of MYSQLCOL constructor
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* MYSQLCOL constructor used for copying columns. */
|
|
|
|
/* tdbp is the pointer to the new table descriptor. */
|
|
|
|
/***********************************************************************/
|
|
|
|
MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
|
|
|
|
{
|
|
|
|
Long = col1->Long;
|
|
|
|
Bind = NULL;
|
|
|
|
To_Val = NULL;
|
|
|
|
Slen = col1->Slen;
|
|
|
|
Rank = col1->Rank;
|
|
|
|
} // end of MYSQLCOL copy constructor
|
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
/***********************************************************************/
|
|
|
|
/* FindRank: Find the rank of this column in the result set. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool MYSQLCOL::FindRank(PGLOBAL g)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
MYSQLC myc = ((PTDBMY)To_Tdb)->Myc;
|
|
|
|
|
|
|
|
for (n = 0; n < myc.m_Fields; n++)
|
|
|
|
if (!stricmp(Name, myc.m_Res->fields[n].name)) {
|
|
|
|
Rank = n;
|
|
|
|
return false;
|
|
|
|
} // endif Name
|
|
|
|
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Column %s not in result set", Name);
|
2013-05-19 19:25:06 +02:00
|
|
|
return true;
|
|
|
|
} // end of FindRank
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
/***********************************************************************/
|
|
|
|
/* SetBuffer: prepare a column block for write operation. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool MYSQLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
|
|
|
|
{
|
|
|
|
if (!(To_Val = value)) {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(VALUE_ERROR), Name);
|
2014-04-27 19:18:20 +02:00
|
|
|
return true;
|
2013-02-07 10:34:27 +01:00
|
|
|
} else if (Buf_Type == value->GetType()) {
|
|
|
|
// Values are of the (good) column type
|
|
|
|
if (Buf_Type == TYPE_DATE) {
|
|
|
|
// If any of the date values is formatted
|
|
|
|
// output format must be set for the receiving table
|
|
|
|
if (GetDomain() || ((DTVAL *)value)->IsFormatted())
|
|
|
|
goto newval; // This will make a new value;
|
|
|
|
|
2013-12-28 15:46:49 +01:00
|
|
|
} else if (Buf_Type == TYPE_DOUBLE)
|
2013-02-07 10:34:27 +01:00
|
|
|
// Float values must be written with the correct (column) precision
|
|
|
|
// Note: maybe this should be forced by ShowValue instead of this ?
|
2013-12-28 15:46:49 +01:00
|
|
|
value->SetPrec(GetScale());
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
Value = value; // Directly access the external value
|
|
|
|
} else {
|
|
|
|
// Values are not of the (good) column type
|
|
|
|
if (check) {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(TYPE_VALUE_ERR), Name,
|
2013-02-07 10:34:27 +01:00
|
|
|
GetTypeName(Buf_Type), GetTypeName(value->GetType()));
|
2014-04-27 19:18:20 +02:00
|
|
|
return true;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // endif check
|
|
|
|
|
|
|
|
newval:
|
|
|
|
if (InitValue(g)) // Allocate the matching value block
|
2014-04-27 19:18:20 +02:00
|
|
|
return true;
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} // endif's Value, Buf_Type
|
|
|
|
|
|
|
|
// Because Colblk's have been made from a copy of the original TDB in
|
|
|
|
// case of Update, we must reset them to point to the original one.
|
|
|
|
if (To_Tdb->GetOrig())
|
|
|
|
To_Tdb = (PTDB)To_Tdb->GetOrig();
|
|
|
|
|
|
|
|
// Set the Column
|
|
|
|
Status = (ok) ? BUF_EMPTY : BUF_NO;
|
2014-04-27 19:18:20 +02:00
|
|
|
return false;
|
2013-02-07 10:34:27 +01:00
|
|
|
} // end of SetBuffer
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* InitBind: Initialize the bind structure according to type. */
|
|
|
|
/***********************************************************************/
|
|
|
|
void MYSQLCOL::InitBind(PGLOBAL g)
|
|
|
|
{
|
|
|
|
PTDBMY tdbp = (PTDBMY)To_Tdb;
|
|
|
|
|
|
|
|
assert(tdbp->Bind && Rank < tdbp->Nparm);
|
|
|
|
|
|
|
|
Bind = &tdbp->Bind[Rank];
|
|
|
|
memset(Bind, 0, sizeof(MYSQL_BIND));
|
|
|
|
|
|
|
|
if (Buf_Type == TYPE_DATE) {
|
2013-02-09 01:08:15 +01:00
|
|
|
Bind->buffer_type = PLGtoMYSQL(TYPE_STRING, false);
|
2013-02-07 10:34:27 +01:00
|
|
|
Bind->buffer = (char *)PlugSubAlloc(g,NULL, 20);
|
|
|
|
Bind->buffer_length = 20;
|
|
|
|
Bind->length = &Slen;
|
|
|
|
} else {
|
2013-02-09 01:08:15 +01:00
|
|
|
Bind->buffer_type = PLGtoMYSQL(Buf_Type, false);
|
2013-02-07 10:34:27 +01:00
|
|
|
Bind->buffer = (char *)Value->GetTo_Val();
|
|
|
|
Bind->buffer_length = Value->GetClen();
|
|
|
|
Bind->length = (IsTypeChar(Buf_Type)) ? &Slen : NULL;
|
|
|
|
} // endif Buf_Type
|
|
|
|
|
|
|
|
} // end of InitBind
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* ReadColumn: */
|
|
|
|
/***********************************************************************/
|
|
|
|
void MYSQLCOL::ReadColumn(PGLOBAL g)
|
|
|
|
{
|
2013-11-22 16:03:54 +01:00
|
|
|
char *p, *buf, tim[20];
|
2013-02-07 10:34:27 +01:00
|
|
|
int rc;
|
|
|
|
PTDBMY tdbp = (PTDBMY)To_Tdb;
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* If physical fetching of the line was deferred, do it now. */
|
|
|
|
/*********************************************************************/
|
|
|
|
if (!tdbp->Fetched)
|
2019-04-19 12:15:46 +02:00
|
|
|
{
|
2013-02-07 10:34:27 +01:00
|
|
|
if ((rc = tdbp->Myc.Fetch(g, tdbp->N)) != RC_OK) {
|
|
|
|
if (rc == RC_EF)
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), MSG(INV_DEF_READ), rc);
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2017-03-06 17:23:56 +01:00
|
|
|
throw 11;
|
|
|
|
} else
|
2014-04-27 19:18:20 +02:00
|
|
|
tdbp->Fetched = true;
|
2019-04-19 12:15:46 +02:00
|
|
|
}
|
2013-05-19 19:25:06 +02:00
|
|
|
if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) {
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(2))
|
2013-05-19 19:25:06 +02:00
|
|
|
htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
|
|
|
|
|
2013-11-22 16:03:54 +01:00
|
|
|
// TODO: have a true way to differenciate temporal values
|
2013-12-03 22:59:40 +01:00
|
|
|
if (Buf_Type == TYPE_DATE && strlen(buf) == 8)
|
2013-11-22 16:03:54 +01:00
|
|
|
// This is a TIME value
|
|
|
|
p = strcat(strcpy(tim, "1970-01-01 "), buf);
|
|
|
|
else
|
|
|
|
p = buf;
|
|
|
|
|
2013-12-03 22:59:40 +01:00
|
|
|
if (Value->SetValue_char(p, strlen(p))) {
|
2022-07-19 21:06:55 +02:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Out of range value for column %s at row %d",
|
2013-12-03 22:59:40 +01:00
|
|
|
Name, tdbp->RowNumber(g));
|
|
|
|
PushWarning(g, tdbp);
|
|
|
|
} // endif SetValue_char
|
|
|
|
|
2013-05-19 19:25:06 +02:00
|
|
|
} else {
|
2013-02-24 01:23:18 +01:00
|
|
|
if (Nullable)
|
|
|
|
Value->SetNull(true);
|
|
|
|
|
2013-02-07 10:34:27 +01:00
|
|
|
Value->Reset(); // Null value
|
2013-05-19 19:25:06 +02:00
|
|
|
} // endif buf
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} // end of ReadColumn
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* WriteColumn: make sure the bind buffer is updated. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
void MYSQLCOL::WriteColumn(PGLOBAL)
|
2013-02-07 10:34:27 +01:00
|
|
|
{
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Do convert the column value if necessary. */
|
|
|
|
/*********************************************************************/
|
|
|
|
if (Value != To_Val)
|
2014-04-27 19:18:20 +02:00
|
|
|
Value->SetValue_pval(To_Val, false); // Convert the inserted value
|
2013-02-07 10:34:27 +01:00
|
|
|
|
2013-02-20 16:57:38 +01:00
|
|
|
#if defined(MYSQL_PREPARED_STATEMENTS)
|
2013-02-07 10:34:27 +01:00
|
|
|
if (((PTDBMY)To_Tdb)->Prep) {
|
|
|
|
if (Buf_Type == TYPE_DATE) {
|
2013-06-26 19:42:28 +02:00
|
|
|
Value->ShowValue((char *)Bind->buffer, (int)Bind->buffer_length);
|
2013-02-07 10:34:27 +01:00
|
|
|
Slen = strlen((char *)Bind->buffer);
|
|
|
|
} else if (IsTypeChar(Buf_Type))
|
|
|
|
Slen = strlen(Value->GetCharValue());
|
|
|
|
|
|
|
|
} // endif Prep
|
2013-02-20 16:57:38 +01:00
|
|
|
#endif // MYSQL_PREPARED_STATEMENTS
|
2013-02-07 10:34:27 +01:00
|
|
|
|
|
|
|
} // end of WriteColumn
|
2013-02-11 00:31:03 +01:00
|
|
|
|
2013-10-26 17:14:58 +02:00
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/***********************************************************************/
|
2013-11-06 18:22:09 +01:00
|
|
|
/* Implementation of the TDBMYEXC class. */
|
2013-10-26 17:14:58 +02:00
|
|
|
/***********************************************************************/
|
2014-03-22 08:57:32 +01:00
|
|
|
TDBMYEXC::TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp)
|
2013-11-06 18:22:09 +01:00
|
|
|
{
|
|
|
|
Cmdlist = NULL;
|
|
|
|
Cmdcol = NULL;
|
|
|
|
Shw = false;
|
|
|
|
Havew = false;
|
|
|
|
Isw = false;
|
|
|
|
Warnings = 0;
|
2017-02-16 18:01:48 +01:00
|
|
|
Mxr = tdp->Maxerr;
|
2013-11-06 18:22:09 +01:00
|
|
|
Nerr = 0;
|
|
|
|
} // end of TDBMYEXC constructor
|
|
|
|
|
2015-05-09 17:30:20 +02:00
|
|
|
TDBMYEXC::TDBMYEXC(PTDBMYX tdbp) : TDBMYSQL(tdbp)
|
2013-11-06 18:22:09 +01:00
|
|
|
{
|
|
|
|
Cmdlist = tdbp->Cmdlist;
|
|
|
|
Cmdcol = tdbp->Cmdcol;
|
|
|
|
Shw = tdbp->Shw;
|
|
|
|
Havew = tdbp->Havew;
|
|
|
|
Isw = tdbp->Isw;
|
|
|
|
Mxr = tdbp->Mxr;
|
|
|
|
Nerr = tdbp->Nerr;
|
|
|
|
} // end of TDBMYEXC copy constructor
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
// Is this really useful ???
|
2017-02-16 18:01:48 +01:00
|
|
|
PTDB TDBMYEXC::Clone(PTABS t)
|
2013-10-26 17:14:58 +02:00
|
|
|
{
|
|
|
|
PTDB tp;
|
|
|
|
PCOL cp1, cp2;
|
|
|
|
PGLOBAL g = t->G;
|
|
|
|
|
2015-05-09 17:30:20 +02:00
|
|
|
tp = new(g) TDBMYEXC(this);
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
|
|
|
|
cp2 = new(g) MYXCOL((PMYXCOL)cp1, tp);
|
|
|
|
|
|
|
|
NewPointer(t, cp1, cp2);
|
|
|
|
} // endfor cp1
|
|
|
|
|
|
|
|
return tp;
|
2017-02-16 18:01:48 +01:00
|
|
|
} // end of Clone
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Allocate MYSQL column description block. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PCOL TDBMYEXC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
|
|
{
|
|
|
|
PMYXCOL colp = new(g) MYXCOL(cdp, this, cprec, n);
|
|
|
|
|
|
|
|
if (!colp->Flag)
|
|
|
|
Cmdcol = colp->GetName();
|
|
|
|
|
|
|
|
return colp;
|
|
|
|
} // end of MakeCol
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MakeCMD: make the SQL statement to send to MYSQL connection. */
|
|
|
|
/***********************************************************************/
|
2013-11-06 18:22:09 +01:00
|
|
|
PCMD TDBMYEXC::MakeCMD(PGLOBAL g)
|
2013-10-26 17:14:58 +02:00
|
|
|
{
|
2013-11-06 18:22:09 +01:00
|
|
|
PCMD xcmd = NULL;
|
2013-10-26 17:14:58 +02:00
|
|
|
|
2014-03-10 18:29:04 +01:00
|
|
|
if (To_CondFil) {
|
2013-10-26 17:14:58 +02:00
|
|
|
if (Cmdcol) {
|
2014-03-10 18:29:04 +01:00
|
|
|
if (!stricmp(Cmdcol, To_CondFil->Body) &&
|
|
|
|
(To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
|
|
|
|
xcmd = To_CondFil->Cmds;
|
2013-10-26 17:14:58 +02:00
|
|
|
} else
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Invalid command specification filter");
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
} else
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "No command column in select list");
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
} else if (!Srcdef)
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "No Srcdef default command");
|
2013-10-26 17:14:58 +02:00
|
|
|
else
|
2013-11-06 18:22:09 +01:00
|
|
|
xcmd = new(g) CMD(g, Srcdef);
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
return xcmd;
|
|
|
|
} // end of MakeCMD
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* EXC GetMaxSize: returns the maximum number of rows in the table. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
int TDBMYEXC::GetMaxSize(PGLOBAL)
|
2013-10-26 17:14:58 +02:00
|
|
|
{
|
|
|
|
if (MaxSize < 0) {
|
2013-11-06 18:22:09 +01:00
|
|
|
MaxSize = 10; // a guess
|
2013-10-26 17:14:58 +02:00
|
|
|
} // endif MaxSize
|
|
|
|
|
|
|
|
return MaxSize;
|
|
|
|
} // end of GetMaxSize
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MySQL Exec Access Method opening routine. */
|
|
|
|
/***********************************************************************/
|
|
|
|
bool TDBMYEXC::OpenDB(PGLOBAL g)
|
|
|
|
{
|
|
|
|
if (Use == USE_OPEN) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Multiple execution is not allowed");
|
2013-10-26 17:14:58 +02:00
|
|
|
return true;
|
|
|
|
} // endif use
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Open a MySQL connection for this table. */
|
|
|
|
/* Note: this may not be the proper way to do. Perhaps it is better */
|
|
|
|
/* to test whether a connection is already open for this server */
|
|
|
|
/* and if so to allocate just a new result set. But this only for */
|
|
|
|
/* servers allowing concurency in getting results ??? */
|
|
|
|
/*********************************************************************/
|
|
|
|
if (!Myc.Connected())
|
2017-02-16 18:01:48 +01:00
|
|
|
if (Myc.Open(g, Host, Schema, User, Pwd, Port))
|
2013-10-26 17:14:58 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
Use = USE_OPEN; // Do it now in case we are recursively called
|
|
|
|
|
2014-04-19 17:02:53 +02:00
|
|
|
if (Mode != MODE_READ && Mode != MODE_READX) {
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "No INSERT/DELETE/UPDATE of MYSQL EXEC tables");
|
2013-10-26 17:14:58 +02:00
|
|
|
return true;
|
|
|
|
} // endif Mode
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Get the command to execute. */
|
|
|
|
/*********************************************************************/
|
2013-11-06 18:22:09 +01:00
|
|
|
if (!(Cmdlist = MakeCMD(g))) {
|
2018-05-07 22:43:43 +02:00
|
|
|
// Next lines commented out because of CHECK TABLE
|
|
|
|
//Myc.Close();
|
|
|
|
//return true;
|
2014-10-21 17:29:51 +02:00
|
|
|
} // endif Cmdlist
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
} // end of OpenDB
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* Data Base read routine for MYSQL access method. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYEXC::ReadDB(PGLOBAL g)
|
|
|
|
{
|
2013-11-06 18:22:09 +01:00
|
|
|
if (Havew) {
|
|
|
|
// Process result set from SHOW WARNINGS
|
|
|
|
if (Myc.Fetch(g, -1) != RC_OK) {
|
|
|
|
Myc.FreeResult();
|
|
|
|
Havew = Isw = false;
|
|
|
|
} else {
|
|
|
|
N++;
|
|
|
|
Isw = true;
|
|
|
|
return RC_OK;
|
|
|
|
} // endif Fetch
|
|
|
|
|
|
|
|
} // endif m_Res
|
|
|
|
|
|
|
|
if (Cmdlist) {
|
|
|
|
// Process query to send
|
|
|
|
int rc;
|
2014-03-22 08:57:32 +01:00
|
|
|
|
2013-11-06 18:22:09 +01:00
|
|
|
do {
|
2014-10-21 17:29:51 +02:00
|
|
|
if (Query)
|
|
|
|
Query->Set(Cmdlist->Cmd);
|
|
|
|
else
|
|
|
|
Query = new(g) STRING(g, 0, Cmdlist->Cmd);
|
2013-11-06 18:22:09 +01:00
|
|
|
|
2014-10-21 17:29:51 +02:00
|
|
|
switch (rc = Myc.ExecSQLcmd(g, Query->GetStr(), &Warnings)) {
|
2013-11-06 18:22:09 +01:00
|
|
|
case RC_NF:
|
|
|
|
AftRows = Myc.m_Afrw;
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Affected rows");
|
2013-11-06 18:22:09 +01:00
|
|
|
break;
|
|
|
|
case RC_OK:
|
|
|
|
AftRows = Myc.m_Fields;
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "Result set columns");
|
2013-11-06 18:22:09 +01:00
|
|
|
break;
|
|
|
|
case RC_FX:
|
|
|
|
AftRows = Myc.m_Afrw;
|
|
|
|
Nerr++;
|
|
|
|
break;
|
|
|
|
case RC_INFO:
|
|
|
|
Shw = true;
|
|
|
|
} // endswitch rc
|
2014-03-22 08:57:32 +01:00
|
|
|
|
2013-11-06 18:22:09 +01:00
|
|
|
Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
|
|
|
|
} while (rc == RC_INFO);
|
|
|
|
|
|
|
|
if (Shw && Warnings)
|
|
|
|
Havew = (Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK);
|
|
|
|
|
|
|
|
++N;
|
|
|
|
return RC_OK;
|
2018-05-07 22:43:43 +02:00
|
|
|
} else {
|
|
|
|
PushWarning(g, this, 1);
|
|
|
|
return RC_EF;
|
|
|
|
} // endif Cmdlist
|
2013-11-06 18:22:09 +01:00
|
|
|
|
2013-10-26 17:14:58 +02:00
|
|
|
} // end of ReadDB
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* WriteDB: Data Base write routine for Exec MYSQL access methods. */
|
|
|
|
/***********************************************************************/
|
|
|
|
int TDBMYEXC::WriteDB(PGLOBAL g)
|
|
|
|
{
|
2023-03-10 23:41:11 +01:00
|
|
|
snprintf(g->Message, sizeof(g->Message), "EXEC MYSQL tables are read only");
|
2013-10-26 17:14:58 +02:00
|
|
|
return RC_FX;
|
|
|
|
} // end of WriteDB
|
|
|
|
|
|
|
|
// ------------------------- MYXCOL functions ---------------------------
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MYXCOL public constructor. */
|
|
|
|
/***********************************************************************/
|
2017-05-11 21:57:21 +02:00
|
|
|
MYXCOL::MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
|
2013-10-26 17:14:58 +02:00
|
|
|
: MYSQLCOL(cdp, tdbp, cprec, i, am)
|
|
|
|
{
|
|
|
|
// Set additional EXEC MYSQL access method information for column.
|
|
|
|
Flag = cdp->GetOffset();
|
|
|
|
} // end of MYSQLCOL constructor
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MYSQLCOL public constructor. */
|
|
|
|
/***********************************************************************/
|
2017-05-11 21:57:21 +02:00
|
|
|
MYXCOL::MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
|
2013-10-26 17:14:58 +02:00
|
|
|
: MYSQLCOL(fld, tdbp, i, am)
|
|
|
|
{
|
2018-04-24 20:28:31 +02:00
|
|
|
if (trace(1))
|
2013-10-26 17:14:58 +02:00
|
|
|
htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
|
|
|
|
|
|
|
|
} // end of MYSQLCOL constructor
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* MYXCOL constructor used for copying columns. */
|
|
|
|
/* tdbp is the pointer to the new table descriptor. */
|
|
|
|
/***********************************************************************/
|
|
|
|
MYXCOL::MYXCOL(MYXCOL *col1, PTDB tdbp) : MYSQLCOL(col1, tdbp)
|
|
|
|
{
|
|
|
|
Flag = col1->Flag;
|
|
|
|
} // end of MYXCOL copy constructor
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* ReadColumn: */
|
|
|
|
/***********************************************************************/
|
|
|
|
void MYXCOL::ReadColumn(PGLOBAL g)
|
|
|
|
{
|
|
|
|
PTDBMYX tdbp = (PTDBMYX)To_Tdb;
|
|
|
|
|
2013-11-06 18:22:09 +01:00
|
|
|
if (tdbp->Isw) {
|
|
|
|
char *buf = NULL;
|
|
|
|
|
|
|
|
if (Flag < 3) {
|
|
|
|
buf = tdbp->Myc.GetCharField(Flag);
|
|
|
|
Value->SetValue_psz(buf);
|
|
|
|
} else
|
|
|
|
Value->Reset();
|
|
|
|
|
|
|
|
} else
|
|
|
|
switch (Flag) {
|
2014-10-21 17:29:51 +02:00
|
|
|
case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
|
|
|
|
case 1: Value->SetValue(tdbp->AftRows); break;
|
|
|
|
case 2: Value->SetValue_psz(g->Message); break;
|
|
|
|
case 3: Value->SetValue(tdbp->Warnings); break;
|
|
|
|
default: Value->SetValue_psz("Invalid Flag"); break;
|
2013-11-06 18:22:09 +01:00
|
|
|
} // endswitch Flag
|
2013-10-26 17:14:58 +02:00
|
|
|
|
|
|
|
} // end of ReadColumn
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* WriteColumn: should never be called. */
|
|
|
|
/***********************************************************************/
|
2015-05-09 17:30:20 +02:00
|
|
|
void MYXCOL::WriteColumn(PGLOBAL)
|
2013-10-26 17:14:58 +02:00
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
} // end of WriteColumn
|
|
|
|
|
2013-02-11 00:31:03 +01:00
|
|
|
/* ---------------------------TDBMCL class --------------------------- */
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* TDBMCL class constructor. */
|
|
|
|
/***********************************************************************/
|
|
|
|
TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp)
|
|
|
|
{
|
2014-03-22 08:57:32 +01:00
|
|
|
Host = tdp->Hostname;
|
2017-02-16 18:01:48 +01:00
|
|
|
Db = tdp->Tabschema;
|
2014-03-22 08:57:32 +01:00
|
|
|
Tab = tdp->Tabname;
|
|
|
|
User = tdp->Username;
|
|
|
|
Pwd = tdp->Password;
|
2013-02-11 00:31:03 +01:00
|
|
|
Port = tdp->Portnumber;
|
|
|
|
} // end of TDBMCL constructor
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
/* GetResult: Get the list the MYSQL table columns. */
|
|
|
|
/***********************************************************************/
|
|
|
|
PQRYRES TDBMCL::GetResult(PGLOBAL g)
|
|
|
|
{
|
2014-03-30 22:52:54 +02:00
|
|
|
return MyColumns(g, NULL, Host, Db, User, Pwd, Tab, NULL, Port, false);
|
2014-03-22 08:57:32 +01:00
|
|
|
} // end of GetResult
|