Modified:
trunk/MYSQLPlus/MYSQLPlusLib/MCommand.cpp
trunk/MYSQLPlus/MYSQLPlusLib/MCommand.h
trunk/MYSQLPlus/MYSQLPlusLib/MYSQLPlusLib.vpj
trunk/MYSQLPlus/include/MStatement.h
Log:
more fleshing out MCommand
Modified: trunk/MYSQLPlus/MYSQLPlusLib/MCommand.cpp
===================================================================
--- trunk/MYSQLPlus/MYSQLPlusLib/MCommand.cpp 2006-07-10 16:02:49 UTC (rev 435)
+++ trunk/MYSQLPlus/MYSQLPlusLib/MCommand.cpp 2006-07-10 20:05:53 UTC (rev 436)
@@ -16,6 +16,8 @@
this->pConnection = pConnection;
pStatement = NULL;
+ nCommandType = COMMAND_TYPE_NULL;
+
MYODBCDbgReturn2();
}
@@ -27,41 +29,99 @@
this->pStatement = pStatement;
pConnection = pStatement->getConnection();
+ nCommandType = COMMAND_TYPE_NULL;
+
MYODBCDbgReturn2();
}
/*!
\brief Causes the given command to be prepared.
- We separate the commands by ';' and create an MCommand for each.
+ Here we prepare the command so as to;
- The MCommand will do the remaining processing.
+ - translate any ODBC specific syntax into syntax supported by the server
(ie "{d <dateval>}" )
+ - process escape sequences as needed
+ - provide parameter marker information
+ - provide feature information (ie is command viable for a transaction)
\return SQLRETURN
+
+ \retval SQL_SUCCESS Success.
+ \retval SQL_SUCCESS_WITH_INFO Warning(s) have been put into diagnostic. We can
continue.
+ \retval SQL_ERROR Error(s) have been put into diagnostic. We can
not continue.
*/
-SQLRETURN MCommands::setCommand( const QString &stringCommands )
+SQLRETURN MCommand::setCommand( const QString &stringCommand )
{
MYODBCDbgEnter();
- QChar cQuote;
- QChar cMarker( '?' );
- QChar cBraceOpen( '{' );
- QChar cBraceClose( '}' );
- int nBraceNest = 0;
- BOOLEAN bBraceCheck = true;
- QString stringQuotes = "\"'";
- QString stringStatementSegment;
+ /*!
+ \internal
+ \note
- for ( int nChar = 0; nChar < stringStatement.length(); nChar++ )
+ At the moment - we are just doing the following in here;
+
+ - strip off any curly braces used on entire command ie "{ CALL sp() }" becomes "
CALL sp() "
+ - get index pos for each parameter marker (without removing marker)
+ - get command type based upon first keyword
+
+ As a side affect we are usually (but not always) going to catch;
+
+ - mismatched quotes
+ - mismatched braces
+
+ \todo
+
+ - translate ODBC specific syntax to server friendly
+ - handle escape sequences as needed
+ - get details about commands within store procedures so we can report command
features etc (probably not practical to do this)
+ */
+ SQLRETURN nReturn = SQL_SUCCESS;
+ QChar cQuote;
+ QChar cMarker( '?' );
+ QChar cBraceOpen( '{' );
+ QChar cBraceClose( '}' );
+ int nBraceNest = 0;
+ BOOLEAN bBraceCheck = true;
+ QString stringQuotes = "\"'";
+
+ /* clear any existing processing */
+ nCommandType = COMMAND_TYPE_NULL;
+ listParameterMarkers.clear();
+ stringCommand.clear();
+ stringCommandNative.clear();
+
+ /* for each char in stringCommand */
+ for ( int nChar = 0, int nCharsSkipped = 0; nChar < stringCommand.length();
nChar++ )
{
- QChar cChar = stringStatement.at( nChar );
+ QChar cChar = stringCommand.at( nChar );
+ BOOLEAN bLastChar = ( nChar == (stringCommand.length() - 1) );
+ /* catch some last char problems */
+ if ( bLastChar )
+ {
+ /* mismatched quote */
+ if ( ( !cQuote.isNull() && cChar != cQuote ) || /*
last char is not going to close our quote */
+ ( cQuote.isNull() && stringQuotes.contains( cChar ) ) ) /*
last char is going to open a quote */
+ MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000, 0,
QString( tr("mismatched quote near: ") ).arg( stringCommand ) ) );
+
+ /* mismatched brace */
+ if ( bBraceCheck &&
+ (nBraceNest && cChar != cBraceClose) ||
+ (nBraceNest == 0 && cChar == cBraceOpen || cChar == cBraceClose)
||
+ nBraceNest > 1 ||
+ nBraceNest < 0 )
+ MYODBCDbgReturn( getDiagnostic()->doAppend( MDiagnostic::DIA_HY000, 0,
QString( tr("mismatched brace near: ") ).arg( stringCommand ) ) );
+ }
+
/* brace opening (not in quotes) */
if ( bBraceCheck && cQuote.isNull() && cChar == cBraceOpen )
{
nBraceNest++;
if ( nBraceNest == 1 )
+ {
+ nCharsSkipped++;
continue;
+ }
}
/* brace closing (not in quotes) */
@@ -71,6 +131,7 @@
if ( nBraceNest == 0 )
{
bBraceCheck = false;
+ nCharsSkipped++;
continue;
}
}
@@ -81,13 +142,7 @@
/* parameter marker */
if ( cQuote.isNull() && cChar == cMarker )
- {
- if ( !stringStatementSegment.isNull() )
- stringlistStatement += stringStatementSegment;
- stringlistStatement += QString( cMarker );
- stringStatementSegment.clear();
- continue;
- }
+ listParameterMarkers.append( nChar - nCharsSkipped );
/* quote opening */
if ( cQuote.isNull() && stringQuotes.contains( cChar ) )
@@ -96,13 +151,42 @@
else if ( !cQuote.isNull() && cQuote == cChar )
cQuote = '\0';
- stringStatementSegment += cChar;
+ this->stringCommand += cChar;
}
- if ( !stringStatementSegment.isNull() )
- stringlistStatement += stringStatementSegment;
- this->stringCommand = stringCommand;
+ this->stringCommand = this->stringCommand.trimmed();
+ /*!
+ \internal
+
+ determine command type
+
+ \todo
+
+ - detect SELECT INTO
+ - support for more keywords/types
+ */
+ if ( this->stringCommand.startWith( "SELECT " ) )
+ nCommandType = COMMAND_TYPE_SELECT;
+ else if ( this->stringCommand.startWith( "SHOW " ) )
+ nCommandType = COMMAND_TYPE_SHOW;
+ else if ( this->stringCommand.startWith( "UPDATE " ) )
+ nCommandType = COMMAND_TYPE_UPDATE;
+ else if ( this->stringCommand.startWith( "DELETE " ) )
+ nCommandType = COMMAND_TYPE_DELETE;
+ else if ( this->stringCommand.startWith( "INSERT " ) )
+ nCommandType = COMMAND_TYPE_INSERT;
+ else if ( this->stringCommand.startWith( "CALL " ) )
+ nCommandType = COMMAND_TYPE_CALL;
+ else if ( this->stringCommand.startWith( "CREATE " ) )
+ nCommandType = COMMAND_TYPE_CREATE;
+ else if ( this->stringCommand.startWith( "GRANT " ) )
+ nCommandType = COMMAND_TYPE_GRANT;
+ else if ( this->stringCommand.startWith( "SET " ) )
+ nCommandType = COMMAND_TYPE_SET;
+ else
+ nCommandType = COMMAND_TYPE_UNKNOWN;
+
MYODBCDbgReturn( nReturn );
}
@@ -111,7 +195,7 @@
\return QString
*/
-QString MCommands::getCommand()
+QString MCommand::getCommand()
{
MYODBCDbgEnter();
@@ -127,7 +211,7 @@
\return QString
*/
-QString MCommands::getCommandNative()
+QString MCommand::getCommandNative()
{
MYODBCDbgEnter();
@@ -142,28 +226,99 @@
\return QList<int>
*/
-QList<int> MCommands::getParameterMarkers()
+QList<int> MCommand::getParameterMarkers()
{
MYODBCDbgEnter();
MYODBCDbgReturn3( "%p", listParameterMarkers );
}
+BOOLEAN MCommand::isDataManipulationLanguage()
+{
+ MYODBCDbgEnter();
+
+ /*!
+ \note
+
+ We classify CALL as both DML and DDL. At some point this code will need to know
for certian.
+ */
+ switch ( nCommandType )
+ {
+ case COMMAND_TYPE_SELECT:
+ case COMMAND_TYPE_SELECT_INTO:
+ case COMMAND_TYPE_SHOW:
+ case COMMAND_TYPE_UPDATE:
+ case COMMAND_TYPE_DELETE:
+ case COMMAND_TYPE_INSERT:
+ case COMMAND_TYPE_CALL:
+ case COMMAND_TYPE_SET:
+ MYODBCDbgReturn3( "%d", true );
+ case COMMAND_TYPE_CREATE:
+ case COMMAND_TYPE_GRANT:
+ case COMMAND_TYPE_NULL:
+ case COMMAND_TYPE_UNKNOWN:
+ }
+
+ MYODBCDbgReturn3( "%d", false );
+}
+
+BOOLEAN MCommand::isDataDefinitionLanguage()
+{
+ MYODBCDbgEnter();
+
+ /*!
+ \note
+
+ We classify CALL as both DML and DDL. At some point this code will need to know
for certian.
+ */
+ switch ( nCommandType )
+ {
+ case COMMAND_TYPE_CALL:
+ case COMMAND_TYPE_CREATE:
+ case COMMAND_TYPE_GRANT:
+ MYODBCDbgReturn3( "%d", true );
+ case COMMAND_TYPE_SELECT:
+ case COMMAND_TYPE_SELECT_INTO:
+ case COMMAND_TYPE_SHOW:
+ case COMMAND_TYPE_UPDATE:
+ case COMMAND_TYPE_DELETE:
+ case COMMAND_TYPE_INSERT:
+ case COMMAND_TYPE_SET:
+ case COMMAND_TYPE_NULL:
+ case COMMAND_TYPE_UNKNOWN:
+ }
+
+ MYODBCDbgReturn3( "%d", false );
+}
+
/*!
\brief Used to determine if command is going to honour any transaction it may be a
party to.
This may be used to enforce ODBC rules during a prepare.
+ \note This does NOT factor in;
+
+ - whether or not the server supports transactions
+ - whether or not the driver has been told to use transactions
+ - whether or not database objects (tables) referenced support transactions
+
\return BOOLEAN
\retval true If command will honour a transaction.
\retval false If command will not honour a transaction.
*/
-BOOLEAN MCommands::isTransactionPossible()
+BOOLEAN MCommand::isTransactionPossible()
{
MYODBCDbgEnter();
+ /*!
+ \internal MYSQL RULE
+ We support transactions on DML commands (not on DDL).
+ */
+ if ( isDataManipulationLanguage() )
+ MYODBCDbgReturn3( "%d", true );
+
MYODBCDbgReturn3( "%d", false );
}
@@ -181,10 +336,32 @@
\retval true If command will create a result-set.
\retval false If command will not create a result-set.
*/
-BOOLEAN MCommands::isResultSetPossible()
+BOOLEAN MCommand::isResultSetPossible()
{
MYODBCDbgEnter();
+ /*!
+ \note
+
+ We assume CALL produces a result-set. At some point this code will need to know
for certian.
+ */
+ switch ( nCommandType )
+ {
+ case COMMAND_TYPE_CALL:
+ case COMMAND_TYPE_SELECT:
+ case COMMAND_TYPE_SHOW:
+ MYODBCDbgReturn3( "%d", true );
+ case COMMAND_TYPE_CREATE:
+ case COMMAND_TYPE_GRANT:
+ case COMMAND_TYPE_SELECT_INTO:
+ case COMMAND_TYPE_UPDATE:
+ case COMMAND_TYPE_DELETE:
+ case COMMAND_TYPE_INSERT:
+ case COMMAND_TYPE_SET:
+ case COMMAND_TYPE_NULL:
+ case COMMAND_TYPE_UNKNOWN:
+ }
+
MYODBCDbgReturn3( "%d", false );
}
@@ -200,14 +377,36 @@
\retval true If command may modify data.
\retval false If command will not modify data.
*/
-BOOLEAN MCommands::isDataModificationPossible()
+BOOLEAN MCommand::isDataModificationPossible()
{
MYODBCDbgEnter();
+ /*!
+ \note
+
+ We assume CALL may modify data. At some point this code will need to know for
certian.
+ */
+ switch ( nCommandType )
+ {
+ case COMMAND_TYPE_CALL:
+ case COMMAND_TYPE_CREATE:
+ case COMMAND_TYPE_GRANT:
+ case COMMAND_TYPE_SELECT_INTO:
+ case COMMAND_TYPE_UPDATE:
+ case COMMAND_TYPE_DELETE:
+ case COMMAND_TYPE_INSERT:
+ case COMMAND_TYPE_SET:
+ MYODBCDbgReturn3( "%d", true );
+ case COMMAND_TYPE_SELECT:
+ case COMMAND_TYPE_SHOW:
+ case COMMAND_TYPE_NULL:
+ case COMMAND_TYPE_UNKNOWN:
+ }
+
MYODBCDbgReturn3( "%d", false );
}
-MDiagnostic *MCommands::getDiagnostic()
+MDiagnostic *MCommand::getDiagnostic()
{
if ( pStatement )
pStatement->getDiagnostic();
Modified: trunk/MYSQLPlus/MYSQLPlusLib/MCommand.h
===================================================================
--- trunk/MYSQLPlus/MYSQLPlusLib/MCommand.h 2006-07-10 16:02:49 UTC (rev 435)
+++ trunk/MYSQLPlus/MYSQLPlusLib/MCommand.h 2006-07-10 20:05:53 UTC (rev 436)
@@ -35,17 +35,18 @@
public:
enum COMMAND_TYPE
{
- COMMAND_TYPE_NULL, /*!< we do not have a statement
*/
- COMMAND_TYPE_SELECT, /*!< SELECT statement has been prepared
*/
- COMMAND_TYPE_SELECT_INTO, /*!< SELECT INTO statement has been prepared
*/
- COMMAND_TYPE_SHOW, /*!< SHOW statement has been prepared
*/
- COMMAND_TYPE_UPDATE, /*!< UPDATE statement has been prepared
*/
- COMMAND_TYPE_DELETE, /*!< DELETE statement has been prepared
*/
- COMMAND_TYPE_INSERT, /*!< INSERT statement has been prepared
*/
- COMMAND_TYPE_CALL, /*!< CALL statement has been prepared
*/
- COMMAND_TYPE_CREATE, /*!< CREATE statement has been prepared
*/
- COMMAND_TYPE_GRANT, /*!< GRANT statement has been prepared
*/
- COMMAND_TYPE_SET /*!< SET statement has been prepared
*/
+ COMMAND_TYPE_NULL, /*!< we do not have a command
*/
+ COMMAND_TYPE_SELECT, /*!< SELECT command has been prepared
*/
+ COMMAND_TYPE_SELECT_INTO, /*!< SELECT INTO command has been prepared
*/
+ COMMAND_TYPE_SHOW, /*!< SHOW command has been prepared
*/
+ COMMAND_TYPE_UPDATE, /*!< UPDATE command has been prepared
*/
+ COMMAND_TYPE_DELETE, /*!< DELETE command has been prepared
*/
+ COMMAND_TYPE_INSERT, /*!< INSERT command has been prepared
*/
+ COMMAND_TYPE_CALL, /*!< CALL command has been prepared
*/
+ COMMAND_TYPE_CREATE, /*!< CREATE command has been prepared
*/
+ COMMAND_TYPE_GRANT, /*!< GRANT command has been prepared
*/
+ COMMAND_TYPE_SET, /*!< SET command has been prepared
*/
+ COMMAND_TYPE_UNKNOWN /*!< command starts with unknown keyword
*/
};
MCommand( MConnection *pConnection );
Modified: trunk/MYSQLPlus/MYSQLPlusLib/MYSQLPlusLib.vpj
===================================================================
--- trunk/MYSQLPlus/MYSQLPlusLib/MYSQLPlusLib.vpj 2006-07-10 16:02:49 UTC (rev 435)
+++ trunk/MYSQLPlus/MYSQLPlusLib/MYSQLPlusLib.vpj 2006-07-10 20:05:53 UTC (rev 436)
@@ -52,6 +52,7 @@
<Folder
Name="Source Files"
Filters="*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl">
+ <F N="MCommand.cpp"/>
<F N="MCommands.cpp"/>
<F N="MConnection.cpp"/>
<F N="MDescriptor.cpp"/>
Modified: trunk/MYSQLPlus/include/MStatement.h
===================================================================
--- trunk/MYSQLPlus/include/MStatement.h 2006-07-10 16:02:49 UTC (rev 435)
+++ trunk/MYSQLPlus/include/MStatement.h 2006-07-10 20:05:53 UTC (rev 436)
@@ -5,6 +5,8 @@
class MStatement : public QObject
{
+ friend class MCommands;
+ friend class MCommand;
friend class MStatement;
friend class MConnection;
friend class MResult;
| Thread |
|---|
| • Connector/ODBC 5 commit: r436 - in trunk/MYSQLPlus: MYSQLPlusLib include | pharvey | 10 Jul |