List:Commits« Previous MessageNext Message »
From:pharvey Date:September 18 2006 1:37am
Subject:Connector/ODBC 5 commit: r547 - trunk/SDK/MYSQLPlus/Library
View as plain text  
Modified:
   trunk/SDK/MYSQLPlus/Library/Library.pro
   trunk/SDK/MYSQLPlus/Library/MInternal.h
   trunk/SDK/MYSQLPlus/Library/MResult.cpp
   trunk/SDK/MYSQLPlus/Library/MResult.h
   trunk/SDK/MYSQLPlus/Library/MResultPlus.cpp
   trunk/SDK/MYSQLPlus/Library/MResultPlus.h
   trunk/SDK/MYSQLPlus/Library/MResultRes.cpp
   trunk/SDK/MYSQLPlus/Library/MResultRes.h
Log:
- move work to laptop so i can work and watch kids

Modified: trunk/SDK/MYSQLPlus/Library/Library.pro
===================================================================
--- trunk/SDK/MYSQLPlus/Library/Library.pro	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/Library.pro	2006-09-17 23:37:00 UTC (rev 547)
@@ -7,7 +7,7 @@
 include( ../../../common.pri )
 include( ../../../config.pri )
 include( ../../../defines.pri )
-CONFIG          += staticlib MResultPlus
+CONFIG          += staticlib ResultPlus
 # CONFIG          += staticlib ResultPlus ResultRes ResultStmt
 INCLUDEPATH	+= ../../C/include
 INCLUDEPATH	+= ../../Dbg/include

Modified: trunk/SDK/MYSQLPlus/Library/MInternal.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MInternal.h	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MInternal.h	2006-09-17 23:37:00 UTC (rev 547)
@@ -33,36 +33,19 @@
 class MDescriptorRecordIPD;
 class MDescriptorRecordIRD;
 
-typedef struct tMResultRow
-{
-    /*!
-        \name nStatus
+/*!
+    \internal
+    \note
 
-        nStatus is used to assist in enforcing the following ODBC RULE;
+    Some compilers/version do not support;
 
-                Entries in the row status array state whether each row was fetched
successfully, whether 
-                it was updated, added, or deleted since it was last fetched, and whether
an error occurred 
-                while fetching the row.
+        QVector<QVector<QVariant>>
 
-        So we keep one of the follow in here (not all row status values are viable here);
+    So we typedef. For example; MS VC v7 or older.
+*/
+typedef QVector<QVariant> MResultColumns;
+typedef QVector<MResultColumns> MResultRows;
 
-            SQL_ROW_SUCCESS - row exists and is ready to be used
-            SQL_ROW_UPDATED - row exists and has been updated
-            SQL_ROW_DELETED - row exists but has been deleted 
-            SQL_ROW_ADDED   - row exists and is a newly added row
-
-        \sa SQL_ATTR_CURSOR_SENSITIVITY
-            CURSOR_SENSITIVITY
-    */
-    /*@{*/
-    SQLUSMALLINT        nStatus; 
-    /*@}*/
-    QVector<QVariant>   vectorColumns;
-
-} MResultRow;
-
-typedef QVector<MResultRow> MResultRows;
-
 #include "MCommands.h"
 #include "MCommand.h"
 #include "MDiagnostic.h"

Modified: trunk/SDK/MYSQLPlus/Library/MResult.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResult.cpp	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResult.cpp	2006-09-17 23:37:00 UTC (rev 547)
@@ -752,12 +752,12 @@
 
         No result rows then always return SQL_NO_DATA.
     */
-    if ( !nResultSetRows )
+    if ( !getResultSetRows() )
         MYODBCDbgReturn( setBeforeStart() );
 
     nResultSetRow = 1;
     nRowSetRow    = 1;
-    nRowSetRows   = min( nRowSetSize, nResultSetRows );
+    setRowSetRows( min( nRowSetSize, getResultSetRows() ) );
 
     if ( bRefresh )
         MYODBCDbgReturn( doRefresh() );
@@ -810,7 +810,7 @@
 
         No result rows then always return SQL_NO_DATA.
     */
-    if ( !nResultSetRows )
+    if ( !getResultSetRows() )
         MYODBCDbgReturn( setAfterEnd() );
 
     /*!
@@ -822,11 +822,11 @@
         | RowsetSize [1] <= LastResultRow                               |
LastResultRow         
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nRowSetSize <= nResultSetRows )
+    if ( nRowSetSize <= getResultSetRows() )
     {
-        nResultSetRow = nResultSetRows - nRowSetSize + 1;
+        nResultSetRow = getResultSetRows() - nRowSetSize + 1;
         nRowSetRow    = 1;
-        nRowSetRows   = nRowSetSize;
+        setRowSetRows( nRowSetSize );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -843,11 +843,11 @@
         | RowsetSize [1] > LastResultRow                                | 1           
                     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nRowSetSize > nResultSetRows )
+    if ( nRowSetSize > getResultSetRows() )
     {
         nResultSetRow = 1;
         nRowSetRow    = 1;
-        nRowSetRows   = nResultSetRows;
+        setRowSetRows( getResultSetRows() );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -899,7 +899,7 @@
 
         No result rows then always return SQL_NO_DATA.
     */
-    if ( !nResultSetRows )
+    if ( !getResultSetRows() )
         MYODBCDbgReturn( setBeforeStart() );
 
     /*!
@@ -915,7 +915,7 @@
     {
         nResultSetRow = 1;
         nRowSetRow    = 1;
-        nRowSetRows   = min( nRowSetSize, nResultSetRows );
+        setRowSetRows( min( nRowSetSize, getResultSetRows() ) );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -944,11 +944,11 @@
         | CurrRowsetStart + RowsetSize[1] <= LastResultRow | CurrRowsetStart +
RowsetSize[1] |
        
+--------------------------------------------------+---------------------------------+
     */
-    if ( nResultSetRow + nRowSetSize <= nResultSetRows )
+    if ( nResultSetRow + nRowSetSize <= getResultSetRows() )
     {
         nResultSetRow  += nRowSetSize;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -965,7 +965,7 @@
         | CurrRowsetStart + RowsetSize[1]> LastResultRow   | After end                
      |
        
+--------------------------------------------------+---------------------------------+
     */
-    if ( nResultSetRow + nRowSetSize > nResultSetRows )
+    if ( nResultSetRow + nRowSetSize > getResultSetRows() )
         MYODBCDbgReturn( setAfterEnd() );
 
     MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000, 0, tr("Unknown
condition in doNext().") ) );
@@ -1044,7 +1044,7 @@
     {
         nResultSetRow   = 1;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );        
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
         {
@@ -1069,7 +1069,7 @@
     {
         nResultSetRow  -= nRowSetSize;
         nRowSetRow      = 1;
-        nRowSetRows     = nRowSetSize;
+        setRowSetRows( nRowSetSize );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -1086,11 +1086,11 @@
         | After end AND LastResultRow < RowsetSize[2]      | 1[1]                     
      |
        
+--------------------------------------------------+---------------------------------+
     */
-    if ( isAfterEnd() && nResultSetRows < nRowSetSize )
+    if ( isAfterEnd() && getResultSetRows() < nRowSetSize )
     {
         nResultSetRow   = 1;
         nRowSetRow      = 1;
-        nRowSetRows     = nResultSetRows - nRowSetSize + 1;
+        setRowSetRows( getResultSetRows() - nRowSetSize + 1 );
 
         if ( bRefresh )
         {
@@ -1111,11 +1111,11 @@
         | After end AND LastResultRow >= RowsetSize[2]     | LastResultRow         
+--------------------------------------------------+-----------------------------------+
     */
-    if ( isAfterEnd() && nResultSetRows >= nRowSetSize )
+    if ( isAfterEnd() && getResultSetRows() >= nRowSetSize )
     {
-        nResultSetRow   = nResultSetRows - nRowSetSize;
+        nResultSetRow   = getResultSetRows() - nRowSetSize;
         nRowSetRow      = 1;
-        nRowSetRows     = nRowSetSize;
+        setRowSetRows( nRowSetSize );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -1228,7 +1228,7 @@
     {
         nResultSetRow   = 1;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );        
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
         {
@@ -1249,11 +1249,11 @@
         | 1 <= CurrRowsetStart + FetchOffset <= LastResultRow           |
CurrRowsetStart + FetchOffset     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( 1 <= nResultSetRow + nRows && nResultSetRow + nRows <=
nResultSetRows )
+    if ( 1 <= nResultSetRow + nRows && nResultSetRow + nRows <=
getResultSetRows() )
     {
         nResultSetRow  += nRows;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );        
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -1270,7 +1270,7 @@
         | CurrRowsetStart + FetchOffset > LastResultRow                 | After end   
                     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nResultSetRow + nRows > nResultSetRows )
+    if ( nResultSetRow + nRows > getResultSetRows() )
         MYODBCDbgReturn( setAfterEnd() );
 
     /*!
@@ -1340,11 +1340,11 @@
         | FetchOffset <= LastResultRow                                  |             
                     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nRow < 0 && abs( (long double)nRow ) <= nResultSetRows  )
+    if ( nRow < 0 && abs( (long double)nRow ) <= getResultSetRows()  )
     {
         nResultSetRow  += nRow;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -1363,7 +1363,7 @@
         | FetchOffset > RowsetSize[2]                                   |             
                     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nRow < 0 && abs( (long double)nRow ) > nResultSetRows &&
abs( (long double)nRow ) > nRowSetSize )
+    if ( nRow < 0 && abs( (long double)nRow ) > getResultSetRows()
&& abs( (long double)nRow ) > nRowSetSize )
         MYODBCDbgReturn( setBeforeStart() );
 
     /*!
@@ -1377,11 +1377,11 @@
         | FetchOffset <= RowsetSize[2]                                  |             
                     |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( nRow < 0 && abs( (long double)nRow ) > nResultSetRows &&
abs( (long double)nRow ) <= nRowSetSize )
+    if ( nRow < 0 && abs( (long double)nRow ) > getResultSetRows()
&& abs( (long double)nRow ) <= nRowSetSize )
     {
         nResultSetRow   = 1;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );        
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );
 
         if ( bRefresh )
         {
@@ -1414,11 +1414,11 @@
         | 1 <= FetchOffset <= LastResultRow                             |
FetchOffset                       |
        
+---------------------------------------------------------------+-----------------------------------+
     */
-    if ( 1 <= nRow && nRow <= nResultSetRows )
+    if ( 1 <= nRow && nRow <= getResultSetRows() )
     {
         nResultSetRow   = nRow;
         nRowSetRow      = 1;
-        nRowSetRows     = ( (nResultSetRows - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : nResultSetRows - nResultSetRow + 1 );        
+        setRowSetRows( ( (getResultSetRows() - nResultSetRow + 1) >= nRowSetSize ?
nRowSetSize : getResultSetRows() - nResultSetRow + 1 ) );        
 
         if ( bRefresh )
             MYODBCDbgReturn( doRefresh() );
@@ -1450,7 +1450,7 @@
 BOOLEAN MResult::isAfterEnd()
 {
     MYODBCDbgEnter();
-    MYODBCDbgReturn3( "%d", (nResultSetRow > nResultSetRows) );
+    MYODBCDbgReturn3( "%d", (nResultSetRow > getResultSetRows()) );
 }
 
 BOOLEAN MResult::isValidColumn( SQLUSMALLINT nColumn )
@@ -1495,7 +1495,7 @@
 
     nResultSetRow   = 0;
     nRowSetRow      = 1;
-    nRowSetRows     = 0;
+    setRowSetRows( 0 );
 
     MYODBCDbgReturn( SQL_NO_DATA );
 }
@@ -1504,9 +1504,9 @@
 {
     MYODBCDbgEnter();
 
-    nResultSetRow   = nResultSetRows + 1;
+    nResultSetRow   = getResultSetRows() + 1;
     nRowSetRow      = 1;
-    nRowSetRows     = 0;
+    setRowSetRows( 0 );
 
     MYODBCDbgReturn( SQL_NO_DATA );
 }
@@ -1733,6 +1733,77 @@
     MYODBCDbgReturn2();
 }
 
+/*!
+    \brief  Sets ResultSetRows.
+
+            Derived classes should call this after generating a Result and/or during
+            cursor movement. In the latter case it would be when additional rows are
+            loaded in a ResultSet.
+
+    \note   This will update;
+                - Diagnostic::SQL_DIAG_CURSOR_ROW_COUNT.
+
+    \param  nResultSetRows
+    \param  bResultSetRowsKnown
+*/
+void MResult::setResultSetRows( qulonglong nResultSetRows, BOOLEAN bResultSetRowsKnown )
+{
+    MYODBCDbgEnter();
+
+    getDiagnostic()->setCursorRowCount( (SQLINTEGER)nResultSetRows );
+
+    this->nResultSetRows        = nResultSetRows;
+    this->bResultSetRowsKnown   = bResultSetRowsKnown;
+
+    MYODBCDbgReturn2();
+}
+
+/*!
+    \brief  Sets RowsAffected.
+
+            Derived classes should call this after generating a Result.
+
+    \note   This will update;
+                - Diagnostic::SQL_DIAG_ROW_COUNT
+                - SQLRowCount (value returned from)
+
+    \param  nRowsAffected
+*/
+void MResult::setRowsAffected( qulonglong nRowsAffected )
+{
+    MYODBCDbgEnter();
+
+    getDiagnostic()->setRowCount( (SQLINTEGER)nRowsAffected );
+
+    this->nRowsAffected = nRowsAffected;
+
+    MYODBCDbgReturn2();
+}
+
+/*!
+    \brief  Sets RowSetRows.
+
+            RowSetRows is calculated in MResult based upon the ResultSetRows provided by
derived classes
+            and the ResultSetRow.
+
+    \note   Only call this when its appropriate to update;
+                - IRD::SQL_DESC_ROWS_PROCESSED_PTR.
+
+    \param  nRowSetRows
+*/
+void MResult::setRowSetRows( SQLUINTEGER nRowSetRows )
+{
+    MYODBCDbgEnter();
+
+    SQLUINTEGER *pnRowsProcessedPtr = getImpRowDesc()->getRowsProcessedPtr();
+    if ( pnRowsProcessedPtr )
+        *pnRowsProcessedPtr = nRowSetRows;
+
+    this->nRowSetRows = nRowSetRows;
+
+    MYODBCDbgReturn2();
+}
+
 MYSQL *MResult::getMySQL()
 {
     MYODBCDbgEnter();

Modified: trunk/SDK/MYSQLPlus/Library/MResult.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResult.h	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResult.h	2006-09-17 23:37:00 UTC (rev 547)
@@ -241,6 +241,9 @@
                     Used if;
                         - not CURSOR_TYPE_FORWARD_ONLY and not CONCURRENCY_READ_ONLY 
 
+                    This will be used rarely and only when we want to affect a particular
cursor sensitivity or want a very specific
+                    type of optimization which can be had by having our data buffered in
listRows.
+
                     MYSQLPlus implements CURSOR_TYPE_KEYSET_DRIVEN with the use of
additional buffers which operate in parallel with data 
                     buffers. We do not really support CURSOR_TYPE_DYNAMIC - we just do
same thing as CURSOR_TYPE_KEYSET_DRIVEN. 
     */
@@ -350,14 +353,9 @@
 protected:
     MResultGetData  resultGetData;      /*!< to support getData() (in particular;
chunking)                                                                 */
     MResultSetData  resultSetData;      /*!< to support doSetData() (in particular;
chunking)                                                               */
-    BOOLEAN         bResultSetRowsKnown;/*!< True if we know real value. False if we
are working with highest ResultSetRows we know about & could be more.  */
-    qulonglong      nResultSetRows;     /*!< \todo Get rid of this limitation.        
                                                                     */
-    qulonglong      nRowsAffected;      /*!< number of rows affected by a non-SELECT
statement (catalog and SHOW statements count as SELECT in this case)   */
-    SQLUSMALLINT    nRowSetRow;         /*!< Current row in rowset.                   
                                                                     */
-    SQLUSMALLINT    nRowSetRows;        /*!< Is RowSetSize but will be less when
RowSet goes beyond ResultSetRows.                                          */
 
     /*!
-        \name   listRows
+        \name   vectorRows
 
                 This contains the ResultSet (incl. RowSet) rows or just the RowSet rows
depending 
                 upon the cursor settings.
@@ -366,10 +364,19 @@
                 abstract ourself from this - but for now its a handy solution which meets
our needs.
     */
     /*@{*/
-    MResultRows     vectorRows;
+    MResultRows             vectorRows;
     /*@}*/
 
     /*!
+        \name   vectorStatus
+
+                This contains the status for each row in the RowSet.
+    */
+    /*@{*/
+    QVector<SQLUSMALLINT>   vectorStatus;
+    /*@}*/
+
+    /*!
         \name Statement attributes.
 
         We duplicate these because; 
@@ -396,6 +403,9 @@
     virtual SQLRETURN   setBeforeStart();
     virtual SQLRETURN   setBuffered( BUFFERED bBuffered = BUFFERED_UNBUFFERED );
     SQLRETURN           setGetDataDefault(); // support for getData: this is called when
target C type is SQL_C_DEFAULT  (derive type from IRD)
+    void                setResultSetRows( qulonglong nResultSetRows, BOOLEAN
bResultSetRowsKnown = false );
+    void                setRowsAffected( qulonglong nRowsAffected );
+    void                setRowSetRows( SQLUINTEGER nRowSetRows );
     void                setState( STATE nState );
 
     /* getters */
@@ -420,12 +430,34 @@
     virtual SQLRETURN   doRefreshArray( SQLUINTEGER nRowSetRow );
     virtual SQLRETURN   doRefreshArray( SQLUINTEGER nRowSetRow, SQLUINTEGER nLength );
 
+    /*!
+        \name   Cursor methods.
+
+                Prepares for a cursor call.
+
+                These are implemented in derived classes to;
+
+                    - any underlying cursor is positioned
+                    - ensure that RowSet is loaded with data
+                    - update ResultSetRows as appropriate
+                    - update bResultSetRowsKnown as appropriate
+
+                Derived class may not need to do anything here if;
+
+                    - all data is buffered and RowSet can freely move up/down it
+                    - ResultSetRows is known
+
+                This is the case for MResultPlus and may be the case for others under
+                certian circumstances.
+    */
+    /*@{*/
     virtual SQLRETURN doFirst_() = 0;
     virtual SQLRETURN doGoto_( qulonglong nRow ) = 0;
     virtual SQLRETURN doLast_() = 0;
     virtual SQLRETURN doNext_() = 0;
     virtual SQLRETURN doPrev_() = 0;
     virtual SQLRETURN doSkip_( qlonglong nRowSets ) = 0;
+    /*@}*/
 
     /*!
         \name   from*SQL
@@ -525,16 +557,13 @@
     /*@}*/
 
 private:
-    /*!
-        \internal
-        \note
-
-        Most, if not all, vars that would normally be in here are in 'protected'. This is
to avoid
-        an overly complicated interface to them via derived classes. This is an
exception.
-    */
-
-    BUFFERED    nBuffered;      /*!< where is ResultSet buffered - if at all    */
-    STATE       nState;         /*!< our state                                  */
+    BOOLEAN         bResultSetRowsKnown;    /*!< True if we know real value. False if
we are working with highest ResultSetRows we know about & could be more.  */
+    BUFFERED        nBuffered;              /*!< where is ResultSet buffered - if at
all                                                                        */
+    qulonglong      nResultSetRows;         /*!< \todo qulonglong may be bigger than
SQLUINTEGER but still - see about getting rid of this limitation.          */
+    qulonglong      nRowsAffected;          /*!< number of rows affected by a
non-SELECT statement (catalog and SHOW statements count as SELECT in this case)   */
+    SQLUSMALLINT    nRowSetRow;             /*!< Current row in rowset.               
                                                                         */
+    SQLUSMALLINT    nRowSetRows;            /*!< Is RowSetSize but will be less when
RowSet goes beyond ResultSetRows.                                          */
+    STATE           nState;                 /*!< our state                            
                                                                         */
 };
 
 #endif

Modified: trunk/SDK/MYSQLPlus/Library/MResultPlus.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResultPlus.cpp	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResultPlus.cpp	2006-09-17 23:37:00 UTC (rev 547)
@@ -53,7 +53,7 @@
 
     resultGetData.doClear();
 
-    listResults[ getResultSetRow() - 1 + getRowSetRow() - 1 ].replace( nColumn - 1,
variantData );
+    vectorRows[ getResultSetRow() - 1 + getRowSetRow() - 1 ].vectorColumns.replace(
nColumn - 1, variantData );
 
     MYODBCDbgReturn( SQL_SUCCESS );
 }
@@ -94,11 +94,12 @@
         \internal
         \note
 
-        We do not actually store a bookmark column (we just use row number for that) so
listResults[nRow][0] is 
+        We do not actually store a bookmark column (we just use row number for that) so
vectorRows[nRow].vectorColumns[0] is 
         the first data cell. 
     */
-    listResults.append( QVector<QVariant>( getImpRowDesc()->getCount() ) );
-    nResultSetRow = listResults.count();
+    vectorRows.append( MResultRow );
+    vectorRows.last().nStatus = SQL_ROW_SUCCESS;
+    vectorRows.last().vectorColumns.resize( getImpRowDesc()->getCount() );
 
     MYODBCDbgReturn( SQL_SUCCESS );
 }
@@ -137,6 +138,70 @@
     MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY010, 0,
tr("Resultset is read-only.") ) );
 }
 
+SQLRETURN MResultPlus::doColumnPrivileges( const QString &stringCatalog, const
QString &, const QString &stringTableFilter, const QString
&stringColumnFilter )
+{
+    MYODBCDbgEnter();
+
+    /* create empty resultset */
+    MDescriptor *   pDescriptor     = NULL;
+    SQLRETURN       nReturn         = doApplyCursorRestrictions();
+
+    doClear();
+
+    pDescriptor = getImpRowDesc();
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_SCHEM", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "GRANTOR", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "GRANTEE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "PRIVILEGE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "IS_GRANTABLE", SQL_NULLABLE );
+
+    {
+        QString     stringStatement;
+        MYSQL_RES * pResult = NULL;
+        MYSQL_ROW   pRow;
+
+        stringStatement = "SELECT   TABLE_SCHEMA AS TABLE_CAT, "
+                          "         TABLE_NAME, "
+                          "         COLUMN_NAME, "
+                          "         GRANTEE, "
+                          "         PRIVILEGE_TYPE AS PRIVILEGE, "
+                          "         IS_GRANTABLE "
+                          "FROM     INFORMATION_SCHEMA.TABLE_PRIVILEGES "
+                          "WHERE    TABLE_SCHEMA =    '" + stringCatalog + "' AND "
+                          "         TABLE_NAME   LIKE '" + stringTableFilter + "' AND "
+                          "         COLUMN_NAME  LIKE '" + stringColumnFilter + "' "
+                          "ORDER BY TABLE_CAT, TABLE_NAME, COLUMN_NAME, PRIVILEGE,
GRANTEE";
+
+        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+
+        pResult = mysql_use_result( getMySQL() );
+        if ( !pResult )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+
+        while ( pRow = mysql_fetch_row( pResult ) )
+        {
+            doAppendColumnPrivileges( pRow[0],    // catalog - we put MySQL schema in
here
+                                      pRow[1],    // table name
+                                      pRow[2],    // column name
+                                      pRow[3],    // grantee
+                                      pRow[4],    // privilege 
+                                      pRow[5] );  // is grantable 
+        }
+
+        mysql_free_result( pResult ); 
+    }
+
+    /* set our state */
+    setState( STATE_EXECUTED );
+    setResultSetRows( vectorRows.count(), true );
+
+    MYODBCDbgReturn( nReturn );
+}
+
 SQLRETURN MResultPlus::doColumns( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable, const QString &stringColumn )
 {
     MYODBCDbgEnter();
@@ -147,7 +212,6 @@
     SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
@@ -172,32 +236,9 @@
     /* do it */
     nReturn = doAppendColumnsCatalogs( stringCatalog, stringSchema, stringTable,
stringColumn );
 
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     if ( !SQL_SUCCEEDED(nReturn) )
         MYODBCDbgReturn( nReturn );
@@ -215,7 +256,6 @@
     SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_VARCHAR, "PKTABLE_CAT", SQL_NULLABLE );
@@ -260,32 +300,9 @@
     else if ( !stringFKTable.isEmpty() )
         nReturn = doAppendForeignKeysPKColumns( stringFKCatalog, stringFKSchema,
stringFKTable );
 
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     if ( !SQL_SUCCEEDED(nReturn) )
         MYODBCDbgReturn( nReturn );
@@ -293,7 +310,7 @@
     MYODBCDbgReturn( nReturn2 );
 }
 
-SQLRETURN MResultPlus::doTypeInfo( SQLSMALLINT nDataType )
+SQLRETURN MResultPlus::doPrimaryKeys( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable )
 {
     MYODBCDbgEnter();
 
@@ -302,191 +319,87 @@
     SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
-    pDescriptor->doAppend( SQL_VARCHAR, "TYPE_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "DATA_TYPE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_INTEGER, "COLUMN_SIZE" );
-    pDescriptor->doAppend( SQL_VARCHAR, "LITERAL_PREFIX" );
-    pDescriptor->doAppend( SQL_VARCHAR, "LITERAL_SUFFIX" );
-    pDescriptor->doAppend( SQL_VARCHAR, "CREATE_PARAMS" );
-    pDescriptor->doAppend( SQL_SMALLINT, "NULLABLE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "CASE_SENSITIVE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "SEARCHABLE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "UNSIGNED_ATTRIBUTE" );
-    pDescriptor->doAppend( SQL_SMALLINT, "FIXED_PREC_SCALE" );
-    pDescriptor->doAppend( SQL_SMALLINT, "AUTO_UNIQUE_VALUE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "LOCAL_TYPE_NAME" );
-    pDescriptor->doAppend( SQL_SMALLINT, "MINIMUM_SCALE" );
-    pDescriptor->doAppend( SQL_SMALLINT, "MAXIMUM_SCALE" );
-    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATA_TYPE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATETIME_SUB" );
-    pDescriptor->doAppend( SQL_INTEGER, "NUM_PREC_RADIX" );
-    pDescriptor->doAppend( SQL_SMALLINT, "INTERVAL_PRECISION" );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_SCHEM", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "KEY_SEQ", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "PK_NAME", SQL_NULLABLE );
 
-    /* rows */
-    /* append rows to result */
-    switch ( nDataType )
+    /* load result set */
     {
-        case SQL_ALL_TYPES:
-            doAppendTypeInfoAll();
-            break;
-        case SQL_CHAR:
-            doAppendTypeInfoChar();
-            break;
-        case SQL_VARCHAR:
-            doAppendTypeInfoVarChar();
-            break;
-        case SQL_LONGVARCHAR:
-            doAppendTypeInfoLongVarChar();
-            break;
-        case SQL_WCHAR:
-        case SQL_WVARCHAR:
-        case SQL_WLONGVARCHAR:
-            /*! \todo */
-            break;
-        case SQL_DECIMAL:
-            doAppendTypeInfoDecimal();
-            break;
-        case SQL_NUMERIC:
-            doAppendTypeInfoNumeric();
-            break;
-        case SQL_SMALLINT:
-            doAppendTypeInfoSmallInt();
-            break;
-        case SQL_INTEGER:
-            doAppendTypeInfoInteger();
-            break;
-        case SQL_REAL:
-            doAppendTypeInfoReal();
-            break;
-        case SQL_FLOAT:
-            doAppendTypeInfoFloat();
-            break;
-        case SQL_DOUBLE:
-            doAppendTypeInfoDouble();
-            break;
-        case SQL_BIT:
-            doAppendTypeInfoBit();
-            break;
-        case SQL_TINYINT:
-            doAppendTypeInfoTinyInt();
-            break;
-        case SQL_BIGINT:
-            doAppendTypeInfoBigInt();
-            break;
-        case SQL_BINARY:
-            doAppendTypeInfoBinary();
-            break;
-        case SQL_VARBINARY:
-            doAppendTypeInfoVarBinary();
-            break;
-        case SQL_LONGVARBINARY:
-            doAppendTypeInfoLongVarBinary();
-            break;
-        case SQL_TYPE_DATE:
-            doAppendTypeInfoDate();
-            break;
-        case SQL_TYPE_TIME:
-            doAppendTypeInfoTime();
-            break;
-        case SQL_TYPE_TIMESTAMP:
-            doAppendTypeInfoTimeStamp();
-            break;
-/*    case SQL_TYPE_UTCDATETIME:  */
-/*    case SQL_TYPE_UTCTIME:      */
-        case SQL_INTERVAL_MONTH:
-        case SQL_INTERVAL_YEAR:
-        case SQL_INTERVAL_YEAR_TO_MONTH:
-        case SQL_INTERVAL_DAY:
-        case SQL_INTERVAL_HOUR:
-        case SQL_INTERVAL_MINUTE:
-        case SQL_INTERVAL_SECOND:
-        case SQL_INTERVAL_DAY_TO_HOUR:
-        case SQL_INTERVAL_DAY_TO_MINUTE:
-        case SQL_INTERVAL_DAY_TO_SECOND:
-        case SQL_INTERVAL_HOUR_TO_MINUTE:
-        case SQL_INTERVAL_HOUR_TO_SECOND:
-        case SQL_INTERVAL_MINUTE_TO_SECOND:
-        case SQL_GUID:
-            /*! \todo */
-            break;
-        default:
-            /*
-                \internal ODBC Rule
+        QString     stringStatement;
+        MYSQL_RES * pResult = NULL;
+        MYSQL_ROW   pRow;
 
-                The value specified for the argument DataType was neither a 
-                valid ODBC SQL data type identifier nor a driver-specific data 
-                type identifier supported by the driver.
+        stringStatement = "SELECT COLUMN_NAME, SEQ_IN_INDEX "
+                          "FROM   INFORMATION_SCHEMA.STATISTICS "
+                          "WHERE  TABLE_SCHEMA='" + stringCatalog + "' AND TABLE_NAME='"
+ stringTable + "' AND INDEX_NAME='PRIMARY' "
+                          "ORDER BY SEQ_IN_INDEX ";
 
-                NOTE
+        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
 
-                We only support calling with standard, ODBC, SQL data type or
-                SQL_ALL_TYPES.
-            */
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY004, 0,
NULL ) );
-    }
+        pResult = mysql_use_result( getMySQL() );
+        if ( !pResult )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
 
-    /*!
-        \internal ODBC RULE
+        while ( pRow = mysql_fetch_row( pResult ) )
+        {
+            doAppendPrimaryKeys( stringCatalog,
+                                 stringSchema,
+                                 stringTable,
+                                 pRow[0],
+                                 pRow[1] );
+        }
 
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
+        mysql_free_result( pResult ); 
+    }
 
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     MYODBCDbgReturn( nReturn2 );
 }
 
-SQLRETURN MResultPlus::doPrimaryKeys( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable )
+SQLRETURN MResultPlus::doProcedures( const QString &stringCatalog, const QString
&, const QString &stringProcedure )
 {
     MYODBCDbgEnter();
 
     /* create empty resultset */
     MDescriptor *   pDescriptor;
-    SQLRETURN       nReturn2 = doApplyCursorRestrictions();
+    SQLRETURN       nReturn = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_SCHEM", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "KEY_SEQ", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "PK_NAME", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_CAT", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_SCHEM", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_NAME", SQL_NO_NULLS );
 
-    /* load result set */
+    pDescriptor->doAppend( SQL_SMALLINT, "NUM_INPUT_PARAMS", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "NUM_OUTPUT_PARAMS", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "NUM_RESULT_SETS", SQL_NULLABLE );
+
+    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "PROCEDURE_TYPE", SQL_NO_NULLS );
+
     {
         QString     stringStatement;
         MYSQL_RES * pResult = NULL;
         MYSQL_ROW   pRow;
 
-        stringStatement = "SELECT COLUMN_NAME, SEQ_IN_INDEX "
-                          "FROM   INFORMATION_SCHEMA.STATISTICS "
-                          "WHERE  TABLE_SCHEMA='" + stringCatalog + "' AND TABLE_NAME='"
+ stringTable + "' AND INDEX_NAME='PRIMARY' "
-                          "ORDER BY SEQ_IN_INDEX ";
+        stringStatement = "SELECT   ROUTINE_SCHEMA  AS PROCEDURE_CAT,"
+                          "         ROUTINE_NAME    AS PROCEDURE_NAME,"
+                          "         ROUTINE_COMMENT AS REMARKS,"
+                          "         ROUTINE_TYPE    AS PROCEDURE_TYPE "
+                          "FROM     INFORMATION_SCHEMA.ROUTINES "
+                          "WHERE    ROUTINE_SCHEMA =    '" + stringCatalog + "' AND "
+                          "         ROUTINE_NAME   LIKE '" + stringProcedure + "' "
+                          "ORDER BY PROCEDURE_CAT, PROCEDURE_NAME";
 
         if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
             MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
@@ -497,44 +410,114 @@
 
         while ( pRow = mysql_fetch_row( pResult ) )
         {
-            doAppendPrimaryKeys( stringCatalog,
-                                 stringSchema,
-                                 stringTable,
-                                 pRow[0],
-                                 pRow[1] );
+            SQLSMALLINT nType;
+            QString stringType( pRow[3] );
+
+            if ( stringType == "FUNCTION" )
+                nType = SQL_PT_FUNCTION;
+            else if ( stringType == "PROCEDURE" )
+                nType = SQL_PT_PROCEDURE;
+            else
+            {
+                getDiagnostic()->doAppend( MDiagnostic::DIA_01000, 0,  QString(
"Unhandled procedure type (%1)" ).arg( stringType ) );
+                nType = SQL_PT_UNKNOWN;
+            }
+
+            doAppendProcedures( pRow[0],    // catalog - we put MySQL schema in here
+                                pRow[1],    // procedure name
+                                pRow[2],    // remarks
+                                nType );    // type
         }
 
         mysql_free_result( pResult ); 
     }
 
+    /* set our state */
+    setState( STATE_EXECUTED );
+    setResultSetRows( vectorRows.count(), true );
+
+    MYODBCDbgReturn( nReturn );
+}
+
+SQLRETURN MResultPlus::doProcedureColumns( const QString &stringCatalog, const
QString &, const QString &stringProcedure, const QString &stringColumnFilter
)
+{
+    MYODBCDbgEnter();
+
+    SQLRETURN nReturn = doApplyCursorRestrictions();
+
     /*!
         \internal ODBC RULE
 
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
+        SQLProcedureColumns might not return all columns used by a procedure. For
example, a driver might return 
+        only information about the parameters used by a procedure and not the columns in
a result set it generates.
 
         \internal MYODBC RULE
 
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
+        We only return information on procedure parameters.
     */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
 
+    /* create empty resultset */
+    MDescriptor *pDescriptor;
+
+    doClear();
+
+    pDescriptor = getImpRowDesc();
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_CAT", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_SCHEM", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "COLUMN_TYPE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "DATA_TYPE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "TYPE_NAME", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_INTEGER, "COLUMN_SIZE", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_INTEGER, "BUFFER_LENGTH", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "DECIMAL_DIGITS", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "NUM_PREC_RADIX", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "NULLABLE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_DEF", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATA_TYPE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATETIME_SUB", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_INTEGER, "CHAR_OCTET_LENGTH", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_INTEGER, "ORDINAL_POSITION", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "IS_NULLABLE", SQL_NULLABLE );
+
+    QString stringCreateProcedureCommand;
+    {
+        QString     stringStatement;
+        MYSQL_RES * pResult = NULL;
+        MYSQL_ROW   pRow;
+
+        /*! \todo handle FUNCTION */
+        stringStatement = "SHOW CREATE PROCEDURE ";
+        if ( !stringCatalog.isEmpty() )
+            stringStatement += ( stringCatalog + "." );
+        stringStatement += stringProcedure;
+
+        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+
+        pResult = mysql_use_result( getMySQL() );
+        if ( !pResult )
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+
+        if ( pRow = mysql_fetch_row( pResult ) )
+            stringCreateProcedureCommand = pRow[2];
+
+        mysql_free_result( pResult ); 
+    }
+
+    /* use MCommand to parse params */
+    if ( !stringCreateProcedureCommand.isEmpty() )
+    {
+    }
+MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_IM001 ) );
+
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
-    MYODBCDbgReturn( nReturn2 );
+    MYODBCDbgReturn( nReturn );
 }
 
 SQLRETURN MResultPlus::doSpecialColumns( SQLSMALLINT nIdentifierType, const QString
&stringCatalog, const QString &stringSchema, const QString &stringTable,
SQLSMALLINT nScope, SQLSMALLINT nNullable )
@@ -547,7 +530,6 @@
     SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_SMALLINT, "SCOPE", SQL_NULLABLE );
@@ -584,32 +566,9 @@
         }
     }
 
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     if ( !SQL_SUCCEEDED(nReturn) )
         MYODBCDbgReturn( nReturn );
@@ -634,7 +593,6 @@
     SQLRETURN       nReturn = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
@@ -705,238 +663,13 @@
         mysql_free_result( pResult ); 
     }
 
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     MYODBCDbgReturn( nReturn );
 }
 
-SQLRETURN MResultPlus::doTables( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable, const QString &stringTableType )
-{
-    MYODBCDbgEnter();
-
-    /* create empty resultset */
-    MDescriptor *   pDescriptor;
-    SQLRETURN       nReturn;
-    SQLRETURN       nReturn2 = doApplyCursorRestrictions();
-
-    doClear();
-    getDiagnostic()->setRowCount( 0 );
-
-    pDescriptor = getImpRowDesc();
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_SCHEM", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_TYPE", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
-
-    /* populate resultset */
-    /*!
-        \internal ODBC Rule
-
-        If TableType is SQL_ALL_TABLE_TYPES and CatalogName, SchemaName, and TableName
are 
-        empty strings, the result set contains a list of valid table types for the data
source. 
-        (All columns except the TABLE_TYPE column contain NULLs.) 
-    */
-    if ( ( stringCatalog.isEmpty() && !stringCatalog.isNull() ) &&
-         ( stringSchema.isEmpty() && !stringSchema.isNull() ) &&
-         ( stringTable.isEmpty() && !stringTable.isNull() ) &&
-         stringTableType == SQL_ALL_TABLE_TYPES )
-    {
-        nReturn = doAppendTablesTableTypes();
-    }
-    /*!
-        \internal ODBC Rule
-
-        If SchemaName is SQL_ALL_SCHEMAS and CatalogName and TableName are empty strings,
the result 
-        set contains a list of valid schemas for the data source. (All columns except the
TABLE_SCHEM 
-        column contain NULLs.) 
-    */
-    else if ( ( stringCatalog.isEmpty() && !stringCatalog.isNull() ) &&
-              stringSchema == SQL_ALL_SCHEMAS && 
-              ( stringTable.isEmpty() && !stringTable.isNull() ) )
-    {
-        nReturn = doAppendTablesSchemas();
-    }
-    /*!
-        \internal ODBC Rule
-
-        If CatalogName is SQL_ALL_CATALOGS and SchemaName and TableName are empty
strings, the result set 
-        contains a list of valid catalogs for the data source. (All columns except the
TABLE_CAT column 
-        contain NULLs.) 
-    */
-    else if ( stringCatalog == SQL_ALL_CATALOGS &&
-              ( stringSchema.isEmpty() && !stringSchema.isNull() ) && 
-              ( stringTable.isEmpty() && !stringTable.isNull() )  )
-    {
-        nReturn = doAppendTablesCatalogs();
-    }
-    /*!
-        \internal ODBC Rule
-
-        SQLTables returns the results as a standard result set, ordered by TABLE_TYPE,
TABLE_CAT, TABLE_SCHEM, 
-        and TABLE_NAME.
-    */
-    else
-    {
-        nReturn = doAppendTablesTableTypes( stringCatalog, stringSchema, stringTable,
stringTableType );
-    }
-
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
-    /* set our state */
-    setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
-
-    if ( !SQL_SUCCEEDED( nReturn ) )
-        MYODBCDbgReturn( nReturn );
-
-    MYODBCDbgReturn( nReturn2 );
-}
-
-SQLRETURN MResultPlus::doProcedures( const QString &stringCatalog, const QString
&, const QString &stringProcedure )
-{
-    MYODBCDbgEnter();
-
-    /* create empty resultset */
-    MDescriptor *   pDescriptor;
-    SQLRETURN       nReturn = doApplyCursorRestrictions();
-
-    doClear();
-    getDiagnostic()->setRowCount( 0 );
-
-    pDescriptor = getImpRowDesc();
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_CAT", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_SCHEM", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_NAME", SQL_NO_NULLS );
-
-    pDescriptor->doAppend( SQL_SMALLINT, "NUM_INPUT_PARAMS", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_SMALLINT, "NUM_OUTPUT_PARAMS", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_SMALLINT, "NUM_RESULT_SETS", SQL_NULLABLE );
-
-    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_SMALLINT, "PROCEDURE_TYPE", SQL_NO_NULLS );
-
-    {
-        QString     stringStatement;
-        MYSQL_RES * pResult = NULL;
-        MYSQL_ROW   pRow;
-
-        stringStatement = "SELECT   ROUTINE_SCHEMA  AS PROCEDURE_CAT,"
-                          "         ROUTINE_NAME    AS PROCEDURE_NAME,"
-                          "         ROUTINE_COMMENT AS REMARKS,"
-                          "         ROUTINE_TYPE    AS PROCEDURE_TYPE "
-                          "FROM     INFORMATION_SCHEMA.ROUTINES "
-                          "WHERE    ROUTINE_SCHEMA =    '" + stringCatalog + "' AND "
-                          "         ROUTINE_NAME   LIKE '" + stringProcedure + "' "
-                          "ORDER BY PROCEDURE_CAT, PROCEDURE_NAME";
-
-        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
-
-        pResult = mysql_use_result( getMySQL() );
-        if ( !pResult )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
-
-        while ( pRow = mysql_fetch_row( pResult ) )
-        {
-            SQLSMALLINT nType;
-            QString stringType( pRow[3] );
-
-            if ( stringType == "FUNCTION" )
-                nType = SQL_PT_FUNCTION;
-            else if ( stringType == "PROCEDURE" )
-                nType = SQL_PT_PROCEDURE;
-            else
-            {
-                getDiagnostic()->doAppend( MDiagnostic::DIA_01000, 0,  QString(
"Unhandled procedure type (%1)" ).arg( stringType ) );
-                nType = SQL_PT_UNKNOWN;
-            }
-
-            doAppendProcedures( pRow[0],    // catalog - we put MySQL schema in here
-                                pRow[1],    // procedure name
-                                pRow[2],    // remarks
-                                nType );    // type
-        }
-
-        mysql_free_result( pResult ); 
-    }
-
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
-    /* set our state */
-    setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
-
-    MYODBCDbgReturn( nReturn );
-}
-
 SQLRETURN MResultPlus::doTablePrivileges( const QString &stringCatalog, const QString
&, const QString &stringTableFilter )
 {
     MYODBCDbgEnter();
@@ -946,7 +679,6 @@
     SQLRETURN       nReturn = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
@@ -991,227 +723,232 @@
         mysql_free_result( pResult ); 
     }
 
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
     MYODBCDbgReturn( nReturn );
 }
 
-SQLRETURN MResultPlus::doColumnPrivileges( const QString &stringCatalog, const
QString &, const QString &stringTableFilter, const QString
&stringColumnFilter )
+SQLRETURN MResultPlus::doTables( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable, const QString &stringTableType )
 {
     MYODBCDbgEnter();
 
     /* create empty resultset */
     MDescriptor *   pDescriptor;
-    SQLRETURN       nReturn = doApplyCursorRestrictions();
+    SQLRETURN       nReturn;
+    SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
     pDescriptor->doAppend( SQL_VARCHAR, "TABLE_CAT", SQL_NULLABLE );
     pDescriptor->doAppend( SQL_VARCHAR, "TABLE_SCHEM", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "GRANTOR", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "GRANTEE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "PRIVILEGE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "IS_GRANTABLE", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_NAME", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "TABLE_TYPE", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
 
+    /* populate resultset */
+    /*!
+        \internal ODBC Rule
+
+        If TableType is SQL_ALL_TABLE_TYPES and CatalogName, SchemaName, and TableName
are 
+        empty strings, the result set contains a list of valid table types for the data
source. 
+        (All columns except the TABLE_TYPE column contain NULLs.) 
+    */
+    if ( ( stringCatalog.isEmpty() && !stringCatalog.isNull() ) &&
+         ( stringSchema.isEmpty() && !stringSchema.isNull() ) &&
+         ( stringTable.isEmpty() && !stringTable.isNull() ) &&
+         stringTableType == SQL_ALL_TABLE_TYPES )
     {
-        QString     stringStatement;
-        MYSQL_RES * pResult = NULL;
-        MYSQL_ROW   pRow;
+        nReturn = doAppendTablesTableTypes();
+    }
+    /*!
+        \internal ODBC Rule
 
-        stringStatement = "SELECT   TABLE_SCHEMA AS TABLE_CAT, "
-                          "         TABLE_NAME, "
-                          "         COLUMN_NAME, "
-                          "         GRANTEE, "
-                          "         PRIVILEGE_TYPE AS PRIVILEGE, "
-                          "         IS_GRANTABLE "
-                          "FROM     INFORMATION_SCHEMA.TABLE_PRIVILEGES "
-                          "WHERE    TABLE_SCHEMA =    '" + stringCatalog + "' AND "
-                          "         TABLE_NAME   LIKE '" + stringTableFilter + "' AND "
-                          "         COLUMN_NAME  LIKE '" + stringColumnFilter + "' "
-                          "ORDER BY TABLE_CAT, TABLE_NAME, COLUMN_NAME, PRIVILEGE,
GRANTEE";
-
-        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
-
-        pResult = mysql_use_result( getMySQL() );
-        if ( !pResult )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
-
-        while ( pRow = mysql_fetch_row( pResult ) )
-        {
-            doAppendColumnPrivileges( pRow[0],    // catalog - we put MySQL schema in
here
-                                      pRow[1],    // table name
-                                      pRow[2],    // column name
-                                      pRow[3],    // grantee
-                                      pRow[4],    // privilege 
-                                      pRow[5] );  // is grantable 
-        }
-
-        mysql_free_result( pResult ); 
+        If SchemaName is SQL_ALL_SCHEMAS and CatalogName and TableName are empty strings,
the result 
+        set contains a list of valid schemas for the data source. (All columns except the
TABLE_SCHEM 
+        column contain NULLs.) 
+    */
+    else if ( ( stringCatalog.isEmpty() && !stringCatalog.isNull() ) &&
+              stringSchema == SQL_ALL_SCHEMAS && 
+              ( stringTable.isEmpty() && !stringTable.isNull() ) )
+    {
+        nReturn = doAppendTablesSchemas();
     }
+    /*!
+        \internal ODBC Rule
 
+        If CatalogName is SQL_ALL_CATALOGS and SchemaName and TableName are empty
strings, the result set 
+        contains a list of valid catalogs for the data source. (All columns except the
TABLE_CAT column 
+        contain NULLs.) 
+    */
+    else if ( stringCatalog == SQL_ALL_CATALOGS &&
+              ( stringSchema.isEmpty() && !stringSchema.isNull() ) && 
+              ( stringTable.isEmpty() && !stringTable.isNull() )  )
+    {
+        nReturn = doAppendTablesCatalogs();
+    }
     /*!
-        \internal ODBC RULE
+        \internal ODBC Rule
 
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
+        SQLTables returns the results as a standard result set, ordered by TABLE_TYPE,
TABLE_CAT, TABLE_SCHEM, 
+        and TABLE_NAME.
     */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
     else
-        getDiagnostic()->setRowCount( nRows );
+    {
+        nReturn = doAppendTablesTableTypes( stringCatalog, stringSchema, stringTable,
stringTableType );
+    }
 
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
-    MYODBCDbgReturn( nReturn );
+    if ( !SQL_SUCCEEDED( nReturn ) )
+        MYODBCDbgReturn( nReturn );
+
+    MYODBCDbgReturn( nReturn2 );
 }
 
-SQLRETURN MResultPlus::doProcedureColumns( const QString &stringCatalog, const
QString &, const QString &stringProcedure, const QString &stringColumnFilter
)
+SQLRETURN MResultPlus::doTypeInfo( SQLSMALLINT nDataType )
 {
     MYODBCDbgEnter();
 
-    SQLRETURN nReturn = doApplyCursorRestrictions();
-
-    /*!
-        \internal ODBC RULE
-
-        SQLProcedureColumns might not return all columns used by a procedure. For
example, a driver might return 
-        only information about the parameters used by a procedure and not the columns in
a result set it generates.
-
-        \internal MYODBC RULE
-
-        We only return information on procedure parameters.
-    */
-
     /* create empty resultset */
-    MDescriptor *pDescriptor;
+    MDescriptor *   pDescriptor;
+    SQLRETURN       nReturn2 = doApplyCursorRestrictions();
 
     doClear();
-    getDiagnostic()->setRowCount( 0 );
 
     pDescriptor = getImpRowDesc();
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_CAT", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_SCHEM", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "PROCEDURE_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "COLUMN_TYPE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "DATA_TYPE", SQL_NO_NULLS );
     pDescriptor->doAppend( SQL_VARCHAR, "TYPE_NAME", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_INTEGER, "COLUMN_SIZE", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_INTEGER, "BUFFER_LENGTH", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_SMALLINT, "DECIMAL_DIGITS", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_SMALLINT, "NUM_PREC_RADIX", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "DATA_TYPE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_INTEGER, "COLUMN_SIZE" );
+    pDescriptor->doAppend( SQL_VARCHAR, "LITERAL_PREFIX" );
+    pDescriptor->doAppend( SQL_VARCHAR, "LITERAL_SUFFIX" );
+    pDescriptor->doAppend( SQL_VARCHAR, "CREATE_PARAMS" );
     pDescriptor->doAppend( SQL_SMALLINT, "NULLABLE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "REMARKS", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_VARCHAR, "COLUMN_DEF", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "CASE_SENSITIVE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "SEARCHABLE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_SMALLINT, "UNSIGNED_ATTRIBUTE" );
+    pDescriptor->doAppend( SQL_SMALLINT, "FIXED_PREC_SCALE" );
+    pDescriptor->doAppend( SQL_SMALLINT, "AUTO_UNIQUE_VALUE", SQL_NO_NULLS );
+    pDescriptor->doAppend( SQL_VARCHAR, "LOCAL_TYPE_NAME" );
+    pDescriptor->doAppend( SQL_SMALLINT, "MINIMUM_SCALE" );
+    pDescriptor->doAppend( SQL_SMALLINT, "MAXIMUM_SCALE" );
     pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATA_TYPE", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATETIME_SUB", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_INTEGER, "CHAR_OCTET_LENGTH", SQL_NULLABLE );
-    pDescriptor->doAppend( SQL_INTEGER, "ORDINAL_POSITION", SQL_NO_NULLS );
-    pDescriptor->doAppend( SQL_VARCHAR, "IS_NULLABLE", SQL_NULLABLE );
+    pDescriptor->doAppend( SQL_SMALLINT, "SQL_DATETIME_SUB" );
+    pDescriptor->doAppend( SQL_INTEGER, "NUM_PREC_RADIX" );
+    pDescriptor->doAppend( SQL_SMALLINT, "INTERVAL_PRECISION" );
 
-    QString stringCreateProcedureCommand;
+    /* rows */
+    /* append rows to result */
+    switch ( nDataType )
     {
-        QString     stringStatement;
-        MYSQL_RES * pResult = NULL;
-        MYSQL_ROW   pRow;
+        case SQL_ALL_TYPES:
+            doAppendTypeInfoAll();
+            break;
+        case SQL_CHAR:
+            doAppendTypeInfoChar();
+            break;
+        case SQL_VARCHAR:
+            doAppendTypeInfoVarChar();
+            break;
+        case SQL_LONGVARCHAR:
+            doAppendTypeInfoLongVarChar();
+            break;
+        case SQL_WCHAR:
+        case SQL_WVARCHAR:
+        case SQL_WLONGVARCHAR:
+            /*! \todo */
+            break;
+        case SQL_DECIMAL:
+            doAppendTypeInfoDecimal();
+            break;
+        case SQL_NUMERIC:
+            doAppendTypeInfoNumeric();
+            break;
+        case SQL_SMALLINT:
+            doAppendTypeInfoSmallInt();
+            break;
+        case SQL_INTEGER:
+            doAppendTypeInfoInteger();
+            break;
+        case SQL_REAL:
+            doAppendTypeInfoReal();
+            break;
+        case SQL_FLOAT:
+            doAppendTypeInfoFloat();
+            break;
+        case SQL_DOUBLE:
+            doAppendTypeInfoDouble();
+            break;
+        case SQL_BIT:
+            doAppendTypeInfoBit();
+            break;
+        case SQL_TINYINT:
+            doAppendTypeInfoTinyInt();
+            break;
+        case SQL_BIGINT:
+            doAppendTypeInfoBigInt();
+            break;
+        case SQL_BINARY:
+            doAppendTypeInfoBinary();
+            break;
+        case SQL_VARBINARY:
+            doAppendTypeInfoVarBinary();
+            break;
+        case SQL_LONGVARBINARY:
+            doAppendTypeInfoLongVarBinary();
+            break;
+        case SQL_TYPE_DATE:
+            doAppendTypeInfoDate();
+            break;
+        case SQL_TYPE_TIME:
+            doAppendTypeInfoTime();
+            break;
+        case SQL_TYPE_TIMESTAMP:
+            doAppendTypeInfoTimeStamp();
+            break;
+/*    case SQL_TYPE_UTCDATETIME:  */
+/*    case SQL_TYPE_UTCTIME:      */
+        case SQL_INTERVAL_MONTH:
+        case SQL_INTERVAL_YEAR:
+        case SQL_INTERVAL_YEAR_TO_MONTH:
+        case SQL_INTERVAL_DAY:
+        case SQL_INTERVAL_HOUR:
+        case SQL_INTERVAL_MINUTE:
+        case SQL_INTERVAL_SECOND:
+        case SQL_INTERVAL_DAY_TO_HOUR:
+        case SQL_INTERVAL_DAY_TO_MINUTE:
+        case SQL_INTERVAL_DAY_TO_SECOND:
+        case SQL_INTERVAL_HOUR_TO_MINUTE:
+        case SQL_INTERVAL_HOUR_TO_SECOND:
+        case SQL_INTERVAL_MINUTE_TO_SECOND:
+        case SQL_GUID:
+            /*! \todo */
+            break;
+        default:
+            /*
+                \internal ODBC Rule
 
-        /*! \todo handle FUNCTION */
-        stringStatement = "SHOW CREATE PROCEDURE ";
-        if ( !stringCatalog.isEmpty() )
-            stringStatement += ( stringCatalog + "." );
-        stringStatement += stringProcedure;
+                The value specified for the argument DataType was neither a 
+                valid ODBC SQL data type identifier nor a driver-specific data 
+                type identifier supported by the driver.
 
-        if ( mysql_query( getMySQL(), stringStatement.toUtf8().data() ) )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+                NOTE
 
-        pResult = mysql_use_result( getMySQL() );
-        if ( !pResult )
-            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
-
-        if ( pRow = mysql_fetch_row( pResult ) )
-            stringCreateProcedureCommand = pRow[2];
-
-        mysql_free_result( pResult ); 
+                We only support calling with standard, ODBC, SQL data type or
+                SQL_ALL_TYPES.
+            */
+            MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY004, 0,
NULL ) );
     }
 
-    /* use MCommand to parse params */
-    if ( !stringCreateProcedureCommand.isEmpty() )
-    {
-    }
-MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_IM001 ) );
-
-    /*!
-        \internal ODBC RULE
-
-        When SQLExecute, SQLExecDirect, SQLBulkOperations, SQLSetPos, or SQLMoreResults
is called, the SQL_DIAG_ROW_COUNT 
-        field of the diagnostic data structure is set to the row count, and the row count
is cached in an implementation-dependent 
-        way. SQLRowCount returns the cached row count value. The cached row count value
is valid until the statement handle is set 
-        back to the prepared or allocated state, the statement is reexecuted, or
SQLCloseCursor is called. Note that if a function 
-        has been called since the SQL_DIAG_ROW_COUNT field was set, the value returned by
SQLRowCount might be different from the 
-        value in the SQL_DIAG_ROW_COUNT field because the SQL_DIAG_ROW_COUNT field is
reset to 0 by any function call.                
-
-        \internal MYODBC RULE
-
-        Wet set SQL_DIAG_ROW_COUNT when any result set is requested - for example we also
set SQL_DIAG_ROW_COUNT for catalog
-        functions.
-    */
-    qulonglong nRows = -1;
-    if ( !SQL_SUCCEEDED( getRows( &nRows ) ) )
-        getDiagnostic()->setRowCount( -1 );
-    else
-        getDiagnostic()->setRowCount( nRows );
-
     /* set our state */
     setState( STATE_EXECUTED );
-    nResultSetRows = listResults.count();
-    setResultSetRowsKnown( true );
-    setBeforeStart();
+    setResultSetRows( vectorRows.count(), true );
 
-    MYODBCDbgReturn( nReturn );
+    MYODBCDbgReturn( nReturn2 );
 }
 
 SQLRETURN MResultPlus::doStateRollBack( STATE nState )
@@ -1236,11 +973,10 @@
             break;
 
         case STATE_EXECUTED:
-            listResults.clear();
-            nResultSetRows = 0;
-            setResultSetRowsKnown( false );
-            setBeforeStart();
+            vectorRows.clear();
+            setResultSetRows( 0, true );
             setRowsAffected( 0 );
+            setBeforeStart();
 //            getImpParamDesc()->doClear();
             getImpRowDesc()->doClear();
             resultGetData.doClear();
@@ -1611,24 +1347,24 @@
 }
 
 SQLRETURN MResultPlus::doAppendTypeInfo( const QVariant &stringTypeName,
-                                             const QVariant &nDataType,
-                                             const QVariant &nColumnSize,
-                                             const QVariant &stringLiteralPrefix,
-                                             const QVariant &stringLiteralSuffix,
-                                             const QVariant &nCreateParams,
-                                             const QVariant &nNullable,
-                                             const QVariant &nCaseSensitive,
-                                             const QVariant &nSearchable,
-                                             const QVariant &nUnsignedAttribute,
-                                             const QVariant &nFixedPrecScale,
-                                             const QVariant &nAutoUniqueValue,
-                                             const QVariant &stringLocalTypeName,
-                                             const QVariant &nMinimumScale,
-                                             const QVariant &nMaximumScale,
-                                             const QVariant &nSqlDataType,
-                                             const QVariant &nSqlDateTimeSub,
-                                             const QVariant &nNumPrecRadix,
-                                             const QVariant &nIntervalPrecision )
+                                         const QVariant &nDataType,
+                                         const QVariant &nColumnSize,
+                                         const QVariant &stringLiteralPrefix,
+                                         const QVariant &stringLiteralSuffix,
+                                         const QVariant &nCreateParams,
+                                         const QVariant &nNullable,
+                                         const QVariant &nCaseSensitive,
+                                         const QVariant &nSearchable,
+                                         const QVariant &nUnsignedAttribute,
+                                         const QVariant &nFixedPrecScale,
+                                         const QVariant &nAutoUniqueValue,
+                                         const QVariant &stringLocalTypeName,
+                                         const QVariant &nMinimumScale,
+                                         const QVariant &nMaximumScale,
+                                         const QVariant &nSqlDataType,
+                                         const QVariant &nSqlDateTimeSub,
+                                         const QVariant &nNumPrecRadix,
+                                         const QVariant &nIntervalPrecision )
 {
     MYODBCDbgEnter();
 

Modified: trunk/SDK/MYSQLPlus/Library/MResultPlus.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResultPlus.h	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResultPlus.h	2006-09-17 23:37:00 UTC (rev 547)
@@ -65,7 +65,6 @@
     SQLRETURN doColumnPrivileges( const QString &stringCatalog, const QString
&stringSchemaFilter, const QString &stringTableFilter, const QString
&stringColumnFilter );
     SQLRETURN doColumns( const QString &stringCatalogFilter, const QString
&stringSchemaFilter, const QString &stringTableFilter, const QString
&stringColumnFilter );
     SQLRETURN doForeignKeys( const QString &stringPKCatalog, const QString
&stringPKSchema, const QString &stringPKTable, const QString
&stringFKCatalog, const QString &stringFKSchema, const QString &stringFKTable
);
-    SQLRETURN doTypeInfo( SQLSMALLINT nDataType );
     SQLRETURN doPrimaryKeys( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable );
     SQLRETURN doProcedures( const QString &stringCatalog, const QString
&stringSchemaFilter, const QString &stringProcedureFilter );
     SQLRETURN doProcedureColumns( const QString &stringCatalog, const QString
&stringSchema, const QString &stringProcedure, const QString
&stringColumnFilter );
@@ -73,6 +72,7 @@
     SQLRETURN doStatistics( const QString &stringCatalog, const QString
&stringSchema, const QString &stringTable, SQLUSMALLINT nUnique, SQLUSMALLINT
nReserved );
     SQLRETURN doTablePrivileges( const QString &stringCatalog, const QString
&stringSchemaFilter, const QString &stringTableFilter );
     SQLRETURN doTables( const QString &stringCatalogFilter, const QString
&stringSchemaFilter, const QString &stringTableFilter, const QString
&stringTableTypeFilter );
+    SQLRETURN doTypeInfo( SQLSMALLINT nDataType );
     /*@}*/
 
     /* isers */
@@ -83,13 +83,24 @@
     SQLRETURN doApplyCursorRestrictions();
     SQLRETURN doAppendVarChar();
 
-    SQLRETURN doFirst_()                { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
-    SQLRETURN doGoto_( qulonglong )     { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
-    SQLRETURN doLast_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
-    SQLRETURN doNext_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
-    SQLRETURN doPrev_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
-    SQLRETURN doSkip_( qlonglong )      { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCCESS
); }
+    /*!
+        \name   Cursor methods.
 
+                Prepares for a cursor call.
+
+                We are always a fully buffered BUFFERED_MYSQL_PLUS which means that we
load our entire
+                buffer (ResultSet) up-front and set ResultSetRows accordingly. With that
done we can let
+                MResult and all its default cursor handling work.
+    */
+    /*@{*/
+    SQLRETURN doFirst_()                { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    SQLRETURN doGoto_( qulonglong )     { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    SQLRETURN doLast_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    SQLRETURN doNext_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    SQLRETURN doPrev_()                 { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    SQLRETURN doSkip_( qlonglong )      { MYODBCDbgEnter(); MYODBCDbgReturn( SQL_SUCCESS
); }
+    /*@}*/
+
 private:
     QStringList stringlistTableTypesPossible;   /*!< supports SQLTables */
 

Modified: trunk/SDK/MYSQLPlus/Library/MResultRes.cpp
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResultRes.cpp	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResultRes.cpp	2006-09-17 23:37:00 UTC (rev 547)
@@ -321,6 +321,8 @@
             nRows = mysql_num_rows( pRes );
             if ( mysql_errno( getMySQL() ) )
                 MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000,
mysql_errno( getMySQL() ), mysql_error( getMySQL() ) ) );
+            nResultSetRows      = nRows;
+            bResultSetRowsKnown = true;
         }
 
         getDiagnostic()->setCursorRowCount( nRows );
@@ -334,8 +336,12 @@
         getDiagnostic()->setCursorRowCount( -1 );
         getDiagnostic()->setRowCount( nRows );
         setRowsAffected( nRows );
+        nResultSetRows      = 0;
+        bResultSetRowsKnown = true;
     }
 
+    setBeforeStart();
+
     MYODBCDbgReturn( nReturn );
 }
 
@@ -843,6 +849,8 @@
                                 break;
                             default:
                                 vectorRows[nRow].nStatus = SQL_ROW_ERROR;
+                                getDiagnostic()->setCursorRowCount( nRows );
+                                getDiagnostic()->setRowCount( nRows );
                                 MYODBCDbgReturn( nReturn );
                         }
                     }

Modified: trunk/SDK/MYSQLPlus/Library/MResultRes.h
===================================================================
--- trunk/SDK/MYSQLPlus/Library/MResultRes.h	2006-09-15 19:20:46 UTC (rev 546)
+++ trunk/SDK/MYSQLPlus/Library/MResultRes.h	2006-09-17 23:37:00 UTC (rev 547)
@@ -44,8 +44,10 @@
     SQLRETURN doStateRollBack( STATE nState );
 
     /*!
-        \brief  Prepares for a cursor call.
-    
+        \name   Cursor methods.
+
+                Prepares for a cursor call.
+
                 BUFFERED_UNBUFFERED
 
                     1. Valid only for doNext.    

Thread
Connector/ODBC 5 commit: r547 - trunk/SDK/MYSQLPlus/Librarypharvey18 Sep