diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index f09aa911631..dbfa83a4ce7 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -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; diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 6810321f439..33d181fcfaf 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -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. */ /***********************************************************************/ diff --git a/storage/connect/odbconn.h b/storage/connect/odbconn.h index 24f5898743e..7f1567eaa70 100644 --- a/storage/connect/odbconn.h +++ b/storage/connect/odbconn.h @@ -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 diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp index d27b0f5a3ba..c58091a32fb 100644 --- a/storage/connect/tabodbc.cpp +++ b/storage/connect/tabodbc.cpp @@ -1,11 +1,11 @@ /************* 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: */ /* ----------------------- */ @@ -32,7 +32,7 @@ /***********************************************************************/ /***********************************************************************/ -/* Include relevant MariaDB header file. */ +/* Include relevant MariaDB header file. */ /***********************************************************************/ #include "my_global.h" #if defined(WIN32) @@ -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,12 +128,16 @@ PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m) /* Allocate a TDB of the proper type. */ /* Column blocks will be allocated only when needed. */ /*********************************************************************/ - tdbp = new(g) TDBODBC(this); + if (!Info) { + tdbp = new(g) TDBODBC(this); - if (Multiple == 1) - tdbp = new(g) TDBMUL(tdbp); - else if (Multiple == 2) - strcpy(g->Message, MSG(NO_ODBC_MUL)); + if (Multiple == 1) + tdbp = new(g) TDBMUL(tdbp); + 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 --------------------------- */ diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h index 2b24ebc8e7c..5509d3df679 100644 --- a/storage/connect/tabodbc.h +++ b/storage/connect/tabodbc.h @@ -1,7 +1,7 @@ /*************** 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