Commit 1830e732 authored by Olivier Bertrand's avatar Olivier Bertrand

Make possible to get ODBC DataSources name and description by:

create table datasrc (
`anyname` varchar(256) flag=1,
`anyother name` varchar(256) flag=2)
engine=CONNECT table_type=ODBC option_list='info=yes';

or simply by:

create table datasrc engine=CONNECT table_type=ODBC option_list='info=yes';

then:

select * from datasrc;

Modified:
ha_connect.cc
odbconn.h
odbconn.cpp
tabodbc.h
tabodbc.cpp
parent 9d8d62ee
......@@ -3272,20 +3272,21 @@ bool ha_connect::add_fields(THD *thd, void *alt_info,
bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
{
char ttp= '?', spc= ',', qch= 0, *typn= "DOS";
char *fn, *dsn, *tab, *db, *host, *user, *pwd, *prt, *sep;
char *fn, *dsn, *tab, *db, *host, *user, *pwd, *prt, *sep, *inf;
#if defined(WIN32)
char *nsp= NULL, *cls= NULL;
#endif // WIN32
int port= MYSQL_PORT, hdr= 0, mxr= 0;
bool ok= false;
bool b= false, ok= false, info= false;
LEX *lex= thd->lex;
LEX_STRING *comment, *name;
HA_CREATE_INFO *create_info= (HA_CREATE_INFO *)crt_info;
engine_option_value *pov;
PQRYRES qrp;
PCOLRES crp;
PGLOBAL g= GetPlug(thd);
fn= dsn= tab= db= host= user= pwd= prt= sep= NULL;
fn= dsn= tab= db= host= user= pwd= prt= sep= inf= NULL;
if (g) {
// Set default values
......@@ -3327,15 +3328,18 @@ bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
cls= GetListOption("class", pov->value.str);
#endif // WIN32
mxr= atoi(GetListOption("maxerr", pov->value.str, "0"));
inf= GetListOption("info", pov->value.str);
} // endelse option_list
switch (ttp) {
#if defined(ODBC_SUPPORT)
case 'O': // ODBC
if (!(dsn= create_info->connect_string.str))
info= !!strchr("1yYoO", *inf);
if (!(dsn= create_info->connect_string.str) && !info)
sprintf(g->Message, "Missing %s connection string", typn);
else
ok= true;
ok= !info;
break;
#endif // ODBC_SUPPORT
......@@ -3367,8 +3371,6 @@ bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
if (ok) {
char *length, *decimals, *cnm, *rem;
int i, len, dec;
bool b;
LEX_STRING *comment, *name;
enum_field_types type;
PDBUSER dup= PlgGetUser(g);
PCATLG cat= (dup) ? dup->Catalog : NULL;
......@@ -3407,7 +3409,7 @@ bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
return true;
} // endif qrp
for (i= 0; i < qrp->Nblin; i++) {
for (i= 0; !b && i < qrp->Nblin; i++) {
crp= qrp->Colresp; // Column Name
cnm= encode(g, crp->Kdata->GetCharValue(i));
name= thd->make_lex_string(NULL, cnm, strlen(cnm), true);
......@@ -3440,8 +3442,17 @@ bool ha_connect::pre_create(THD *thd, void *crt_info, void *alt_info)
0, comment, NULL, NULL, NULL);
} // endfor i
return false;
} // endif ttp
return b;
} else if (info) { // ODBC Data Sources
comment= thd->make_lex_string(NULL, "", 0, true);
name= thd->make_lex_string(NULL, "Name", 4, true);
b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
0, comment, NULL, NULL, NULL);
name= thd->make_lex_string(NULL, "Description", 11, true);
b= add_fields(thd, alt_info, name, MYSQL_TYPE_VARCHAR, "256", 0,
0, comment, NULL, NULL, NULL);
return b;
} // endif info
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, g->Message);
return true;
......
......@@ -189,7 +189,6 @@ CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, char *tab, PQRYRES qrp)
#if defined(_DEBUG)
assert(qrp);
#endif
m = (size_t)qrp->Maxres;
n = (size_t)qrp->Nbcol;
cap = (CATPARM *)PlugSubAlloc(g, NULL, sizeof(CATPARM));
......@@ -376,6 +375,50 @@ PQRYRES MyODBCCols(PGLOBAL g, char *tab, char *dsn)
return qrp;
} // end of MyODBCCols
/*************************************************************************/
/* ODBCDataSources: constructs the result blocks containing all ODBC */
/* data sources available on the local host. */
/*************************************************************************/
PQRYRES ODBCDataSources(PGLOBAL g)
{
static int dbtype[] = {DB_CHAR, DB_CHAR};
static int buftyp[] = {TYPE_STRING, TYPE_STRING};
static unsigned int length[] = {0, 256};
int n, ncol = 2;
int maxres;
PQRYRES qrp;
ODBConn *ocp = new(g) ODBConn(g, NULL);
/************************************************************************/
/* Do an evaluation of the result size. */
/************************************************************************/
maxres = 512; // This is completely arbitrary
n = ocp->GetMaxValue(SQL_MAX_DSN_LENGTH);
length[0] = (n) ? (n + 1) : 256;
#ifdef DEBTRACE
htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]);
#endif
/************************************************************************/
/* Allocate the structures used to refer to the result set. */
/************************************************************************/
qrp = PlgAllocResult(g, ncol, maxres, 0, dbtype, buftyp, length);
qrp->Colresp->Name = "Name";
qrp->Colresp->Next->Name = "Description";
/************************************************************************/
/* Now get the results into blocks. */
/************************************************************************/
if (ocp->GetDataSources(qrp))
qrp = NULL;
/************************************************************************/
/* Return the result pointer for use by GetData routines. */
/************************************************************************/
return qrp;
} // end of ODBCDataSources
#if 0 // Currently not used by CONNECT
/***********************************************************************/
/* ODBCTables: constructs the result blocks containing all tables in */
......@@ -1505,6 +1548,50 @@ bool ODBConn::BindParam(ODBCCOL *colp)
return false;
} // end of BindParam
/***********************************************************************/
/* Get the list of Data Sources and set it in qrp. */
/***********************************************************************/
bool ODBConn::GetDataSources(PQRYRES qrp)
{
UCHAR *dsn, *des;
UWORD dir = SQL_FETCH_FIRST;
SWORD n1, n2, p1, p2;
PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
RETCODE rc;
n1 = crp1->Clen;
n2 = crp2->Clen;
try {
rc = SQLAllocEnv(&m_henv);
if (!Check(rc))
ThrowDBX(rc); // Fatal
for (int i = 0; i < qrp->Maxres; i++) {
dsn = (UCHAR*)crp1->Kdata->GetValPtr(i);
des = (UCHAR*)crp2->Kdata->GetValPtr(i);
rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2);
if (rc == SQL_NO_DATA_FOUND)
break;
else if (!Check(rc))
ThrowDBX(rc); // Fatal
qrp->Nblin++;
dir = SQL_FETCH_NEXT;
} // endfor i
} catch(DBX *x) {
strcpy(m_G->Message, x->GetErrorMessage(0));
SQLFreeEnv(m_henv);
return true;
} // end try/catch
SQLFreeEnv(m_henv);
return false;
} // end of GetDataSources
/***********************************************************************/
/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
/***********************************************************************/
......
......@@ -143,6 +143,7 @@ class ODBConn : public BLOCK {
bool ExecuteSQL(void);
bool BindParam(ODBCCOL *colp);
int GetCatInfo(CATPARM *cap);
bool GetDataSources(PQRYRES qrp);
public:
// Set special options
......
/************* Tabodbc C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: TABODBC */
/* ------------- */
/* Version 2.3 */
/* Version 2.4 */
/* */
/* COPYRIGHT: */
/* ---------- */
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
/* */
/* WHAT THIS PROGRAM DOES: */
/* ----------------------- */
......@@ -74,6 +74,7 @@
#include "sql_string.h"
PQRYRES ODBCDataSources(PGLOBAL g);
/***********************************************************************/
/* DB static variables. */
......@@ -83,6 +84,16 @@ extern int num_read, num_there, num_eq[2]; // Statistics
/* -------------------------- Class ODBCDEF -------------------------- */
/***********************************************************************/
/* Constructor. */
/***********************************************************************/
ODBCDEF::ODBCDEF(void)
{
Connect = Tabname = Tabowner = Tabqual = Qchar = NULL;
Catver = Options = 0;
Info = false;
} // end of ODBCDEF constructor
/***********************************************************************/
/* DefineAM: define specific AM block values from XDB file. */
/***********************************************************************/
......@@ -102,6 +113,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Options = Cat->GetIntCatInfo(Name, "Options", dop);
//Options = Cat->GetIntCatInfo(Name, "Options", 0);
Pseudo = 2; // FILID is Ok but not ROWID
Info = Cat->GetBoolCatInfo(Name, "Info", false);
return false;
} // end of DefineAM
......@@ -116,6 +128,7 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
/* Allocate a TDB of the proper type. */
/* Column blocks will be allocated only when needed. */
/*********************************************************************/
if (!Info) {
tdbp = new(g) TDBODBC(this);
if (Multiple == 1)
......@@ -123,6 +136,9 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
else if (Multiple == 2)
strcpy(g->Message, MSG(NO_ODBC_MUL));
} else
tdbp = new(g) TDBOIF(this);
return tdbp;
} // end of GetTable
......@@ -881,4 +897,183 @@ void ODBCCOL::WriteColumn(PGLOBAL g)
} // end of WriteColumn
/* ---------------------------TDBOIF class --------------------------- */
/***********************************************************************/
/* Implementation of the TDBOIF class. */
/***********************************************************************/
TDBOIF::TDBOIF(PODEF tdp) : TDBASE(tdp)
{
Qrp = NULL;
Init = false;
N = -1;
} // end of TDBOIF constructor
/***********************************************************************/
/* Allocate OIF column description block. */
/***********************************************************************/
PCOL TDBOIF::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
{
POIFCOL colp;
colp = (POIFCOL)new(g) OIFCOL(cdp, this, n);
if (cprec) {
colp->SetNext(cprec->GetNext());
cprec->SetNext(colp);
} else {
colp->SetNext(Columns);
Columns = colp;
} // endif cprec
if (!colp->Flag) {
if (!stricmp(colp->Name, "Name"))
colp->Flag = 1;
else if (!stricmp(colp->Name, "Description"))
colp->Flag = 2;
} // endif Flag
return colp;
} // end of MakeCol
/***********************************************************************/
/* Initialize: Get the list of ODBC data sources. */
/***********************************************************************/
bool TDBOIF::Initialize(PGLOBAL g)
{
if (Init)
return false;
if (!(Qrp = ODBCDataSources(g)))
return true;
Init = true;
return false;
} // end of Initialize
/***********************************************************************/
/* OIF: Get the number of properties. */
/***********************************************************************/
int TDBOIF::GetMaxSize(PGLOBAL g)
{
if (MaxSize < 0) {
if (Initialize(g))
return -1;
MaxSize = Qrp->Nblin;
} // endif MaxSize
return MaxSize;
} // end of GetMaxSize
/***********************************************************************/
/* OIF Access Method opening routine. */
/***********************************************************************/
bool TDBOIF::OpenDB(PGLOBAL g)
{
if (Use == USE_OPEN) {
/*******************************************************************/
/* Table already open. */
/*******************************************************************/
N = -1;
return false;
} // endif use
if (Mode != MODE_READ) {
/*******************************************************************/
/* ODBC Info tables cannot be modified. */
/*******************************************************************/
strcpy(g->Message, "OIF tables are read only");
return true;
} // endif Mode
/*********************************************************************/
/* Initialize the ODBC processing. */
/*********************************************************************/
if (Initialize(g))
return true;
return InitCol(g);
} // end of OpenDB
/***********************************************************************/
/* Initialize columns. */
/***********************************************************************/
bool TDBOIF::InitCol(PGLOBAL g)
{
POIFCOL colp;
for (colp = (POIFCOL)Columns; colp; colp = (POIFCOL)colp->GetNext())
switch (colp->Flag) {
case 1:
colp->Crp = Qrp->Colresp;
break;
case 2:
colp->Crp = Qrp->Colresp->Next;
break;
default:
strcpy(g->Message, "Invalid column name or flag");
return true;
} // endswitch Flag
return false;
} // end of InitCol
/***********************************************************************/
/* Data Base read routine for OIF access method. */
/***********************************************************************/
int TDBOIF::ReadDB(PGLOBAL g)
{
return (++N < Qrp->Nblin) ? RC_OK : RC_EF;
} // end of ReadDB
/***********************************************************************/
/* WriteDB: Data Base write routine for OIF access methods. */
/***********************************************************************/
int TDBOIF::WriteDB(PGLOBAL g)
{
strcpy(g->Message, "OIF tables are read only");
return RC_FX;
} // end of WriteDB
/***********************************************************************/
/* Data Base delete line routine for OIF access methods. */
/***********************************************************************/
int TDBOIF::DeleteDB(PGLOBAL g, int irc)
{
strcpy(g->Message, "Delete not enabled for OIF tables");
return RC_FX;
} // end of DeleteDB
/***********************************************************************/
/* Data Base close routine for WMI access method. */
/***********************************************************************/
void TDBOIF::CloseDB(PGLOBAL g)
{
// Nothing to do
} // end of CloseDB
// ------------------------ OIFCOL functions ----------------------------
/***********************************************************************/
/* OIFCOL public constructor. */
/***********************************************************************/
OIFCOL::OIFCOL(PCOLDEF cdp, PTDB tdbp, int n)
: COLBLK(cdp, tdbp, n)
{
Tdbp = (PTDBOIF)tdbp;
Crp = NULL;
Flag = cdp->GetOffset();
} // end of WMICOL constructor
/***********************************************************************/
/* Read the next Data Source elements. */
/***********************************************************************/
void OIFCOL::ReadColumn(PGLOBAL g)
{
// Get the value of the Name or Description property
Value->SetValue_psz(Crp->Kdata->GetCharValue(Tdbp->N));
} // end of ReadColumn
/* ------------------------ End of Tabodbc --------------------------- */
/*************** Tabodbc H Declares Source Code File (.H) **************/
/* Name: TABODBC.H Version 1.4 */
/* Name: TABODBC.H Version 1.5 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
/* (C) Copyright to the author Olivier BERTRAND 2000-2013 */
/* */
/* This file contains the TDBODBC classes declares. */
/***********************************************************************/
......@@ -10,6 +10,8 @@
typedef class ODBCDEF *PODEF;
typedef class TDBODBC *PTDBODBC;
typedef class ODBCCOL *PODBCCOL;
typedef class TDBOIF *PTDBOIF;
typedef class OIFCOL *POIFCOL;
/***********************************************************************/
/* ODBC table. */
......@@ -17,8 +19,7 @@ typedef class ODBCCOL *PODBCCOL;
class DllExport ODBCDEF : public TABDEF { /* Logical table description */
public:
// Constructor
ODBCDEF(void)
{Connect = Tabname = Tabowner = Tabqual = Qchar = NULL; Options = 0;}
ODBCDEF(void);
// Implementation
virtual const char *GetType(void) {return "ODBC";}
......@@ -43,6 +44,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Qchar; /* Identifier quoting character */
int Catver; /* ODBC version for catalog functions */
int Options; /* Open connection options */
bool Info; /* true if getting data sources */
}; // end of ODBCDEF
#if !defined(NODBC)
......@@ -158,5 +160,66 @@ class ODBCCOL : public COLBLK {
SQLLEN Slen; // Used with Fetch
int Rank; // Rank (position) number in the query
}; // end of class ODBCCOL
/***********************************************************************/
/* This is the class declaration for the ODBC info table. */
/***********************************************************************/
class TDBOIF : public TDBASE {
friend class OIFCOL;
public:
// Constructor
TDBOIF(PODEF tdp);
// Implementation
virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
// Methods
virtual int GetRecpos(void) {return N;}
virtual int GetProgCur(void) {return N;}
virtual int RowNumber(PGLOBAL g, bool b = false) {return N + 1;}
// Database routines
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
virtual int GetMaxSize(PGLOBAL g);
virtual bool OpenDB(PGLOBAL g);
virtual int ReadDB(PGLOBAL g);
virtual int WriteDB(PGLOBAL g);
virtual int DeleteDB(PGLOBAL g, int irc);
virtual void CloseDB(PGLOBAL g);
protected:
// Specific routines
bool Initialize(PGLOBAL g);
bool InitCol(PGLOBAL g);
// Members
PQRYRES Qrp;
int N; // Row number
bool Init;
}; // end of class TDBOIF
/***********************************************************************/
/* Class OIFCOL: ODBC info column. */
/***********************************************************************/
class OIFCOL : public COLBLK {
friend class TDBOIF;
public:
// Constructors
OIFCOL(PCOLDEF cdp, PTDB tdbp, int n);
// Implementation
virtual int GetAmType(void) {return TYPE_AM_ODBC;}
// Methods
virtual void ReadColumn(PGLOBAL g);
protected:
OIFCOL(void) {} // Default constructor not to be used
// Members
PTDBOIF Tdbp; // Points to ODBC table block
PCOLRES Crp; // The column data array
int Flag;
}; // end of class OIFCOL
#endif // !NODBC
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment