Nilton, não sei se a classe q vc esta solicitando é a mesma da contrib do Harbour se for vc pode olhar os fontes dentro da pasta contrib\hbmysql
Se for ela abaixo transcrevo parte do código que se refere ao q vc falou, qdo vc usa o Método Query da Classe dependendo sua query ele aciona a criação de um objeto Table ou Query veja:
METHOD Query( cQuery ) CLASS TMySQLServer
LOCAL oQuery, cTableName, i, cUpperQuery, nNumTables, cToken
IF ! ISCHARACTER( cQuery )
cQuery := ""
ENDIF
cUpperQuery := Upper( AllTrim( cQuery ) )
i := 1
nNumTables := 1
DO WHILE !( ( cToken := hb_tokenGet( cUpperQuery, i++, " " ) ) == "FROM" ) .AND. !Empty( cToken )
ENDDO
// first token after "FROM" is a table name
// NOTE: SubSelects ?
cTableName := hb_tokenGet( cUpperQuery, i++, " " )
DO WHILE !( ( cToken := hb_tokenGet( cUpperQuery, i++, " " ) ) == "WHERE" ) .AND. !Empty( cToken )
// do we have more than one table referenced ?
IF cToken == "," .OR. cToken == "JOIN"
nNumTables++
ENDIF
ENDDO
IF nNumTables == 1
oQuery := TMySQLTable():New( ::nSocket, cQuery, cTableName )
ELSE
oQuery := TMySQLQuery():New( ::nSocket, cQuery )
ENDIF
IF oQuery:NetErr()
::lError := .T.
ENDIF
RETURN oQuery
Se for o retorno um objeto a partir da Classe TMySQLQuery o conteudo da mesma segue:
/* ----------------------------------------------------------------------------------------*/
// Every single query submitted to MySQL server
CREATE CLASS TMySQLQuery
VAR nSocket // connection handle to MySQL server
VAR nResultHandle // result handle received from MySQL
VAR cQuery // copy of query that generated this object
VAR nNumRows // number of rows available on answer NOTE MySQL is 0 based
VAR nCurRow // I'm currently over row number
VAR lBof
VAR lEof
VAR lFieldAsData // Use fields as object DATA. For compatibility
// Names of fields can match name of TMySQLQuery/Table DATAs,
// and it is dangerous. ::lFieldAsData:=.F. can fix it
VAR aRow // Values of fields of current row
VAR nNumFields // how many fields per row
VAR aFieldStruct // type of each field, a copy is here a copy inside each row
VAR lError // .T. if last operation failed
METHOD New( nSocket, cQuery ) // New query object
METHOD Destroy()
METHOD End() INLINE ::Destroy()
METHOD Refresh() // ReExecutes the query (cQuery) so that changes to table are visible
METHOD GetRow( nRow ) // return Row n of answer
METHOD Skip( nRows ) // Same as clipper ones
METHOD Bof() INLINE ::lBof //DAVID: ::nCurRow == 1
METHOD Eof() INLINE ::lEof //DAVID: ::nCurRow == ::nNumRows
METHOD RecNo() INLINE ::nCurRow
METHOD LastRec() INLINE ::nNumRows
METHOD GoTop() INLINE ::GetRow( 1 )
METHOD GoBottom() INLINE ::GetRow( ::nNumRows )
METHOD GoTO( nRow ) INLINE ::GetRow( nRow )
METHOD FCount()
METHOD NetErr() INLINE ::lError // Returns .T. if something went wrong
METHOD Error() // Returns textual description of last error and clears ::lError
METHOD FieldName( nNum )
METHOD FieldPos( cFieldName )
METHOD FieldGet( cnField )
METHOD FieldLen( nNum ) // Length of field N
METHOD FieldDec( nNum, lFormat ) // How many decimals in field N
METHOD FieldType( nNum ) // Clipper type of field N
ENDCLASS
METHOD New( nSocket, cQuery ) CLASS TMySQLQuery
LOCAL nI, aField
::nSocket := nSocket
::cQuery := cQuery
::lError := .F.
::aFieldStruct := {}
::nCurRow := 1
::nResultHandle := NIL
::nNumFields := 0
::nNumRows := 0
//DAVID:
::lBof := .T.
::lEof := .T.
::lFieldAsData := .T. //Use fields as object DATA. For compatibility
::aRow := {} //Values of fields of current row
IF mysql_query( nSocket, cQuery ) == 0
// save result set
IF !Empty( ::nResultHandle := mysql_store_result( nSocket ) )
::nNumRows := mysql_num_rows( ::nResultHandle )
::nNumFields := mysql_num_fields( ::nResultHandle )
//DAVID:
::aRow := Array( ::nNumFields )
FOR nI := 1 TO ::nNumFields
aField := mysql_fetch_field( ::nResultHandle )
AAdd( ::aFieldStruct, aField )
//DAVID:
IF ::lFieldAsData
__ObjAddData( Self, ::aFieldStruct[ nI ][ MYSQL_FS_NAME ] )
ENDIF
NEXT
::getRow( ::nCurRow )
ELSE
::nResultHandle := NIL
ENDIF
ELSE
::lError := .T.
ENDIF
RETURN Self
METHOD Refresh() CLASS TMySQLQuery
// free present result handle
::nResultHandle := NIL
::lError := .F.
IF mysql_query( ::nSocket, ::cQuery ) == 0
// save result set
::nResultHandle := mysql_store_result( ::nSocket )
::nNumRows := mysql_num_rows( ::nResultHandle )
// NOTE: I presume that number of fields doesn't change (that is nobody alters this table) between
// successive refreshes of the same
// But row number could very well change
IF ::nCurRow > ::nNumRows
::nCurRow := ::nNumRows
ENDIF
::getRow( ::nCurRow )
ELSE
/* ::aFieldStruct := {}
::nResultHandle := NIL
::nNumFields := 0
::nNumRows := 0
*/
::lError := .T.
ENDIF
RETURN !::lError
METHOD Skip( nRows ) CLASS TMySQLQuery
//DAVID:
LOCAL lbof
// NOTE: MySQL row count starts from 0
IF ! ISNUMBER( nRows )
nRows := 1
ENDIF
//DAVID:
::lBof := Empty( ::LastRec() )
IF nRows == 0
// No move
ELSEIF nRows < 0
// Negative movement
//DAVID: ::nCurRow := Max( ::nCurRow + nRows, 1 )
IF ( ( ::recno() + nRows ) + 0 ) < 1
nRows := - ::recno() + 1
//Clipper: only SKIP movement can set BOF() to .T.
::lBof := .T. //Try to skip before first record
ENDIF
ELSE
// positive movement
//DAVID: ::nCurRow := Min( ::nCurRow + nRows, ::nNumRows )
IF ( ( ::recno() + nRows ) + 0 ) > ::lastrec()
nRows := ::lastrec() - ::recno() + 1
ENDIF
ENDIF
//DAVID:
::nCurRow := ::nCurRow + nRows
//DAVID: maintain ::bof() true until next movement
//Clipper: only SKIP movement can set BOF() to .T.
lbof := ::bof()
// mysql_data_seek( ::nResultHandle, ::nCurRow - 1 )
::getRow( ::nCurrow )
IF lbof
::lBof := .T.
ENDIF
//DAVID: DBSKIP() RETURN NIL RETURN ::nCurRow
RETURN NIL
// Get row n of a query and return it as a TMySQLRow object
METHOD GetRow( nRow ) CLASS TMySQLQuery
//DAVID: replaced by ::aRow LOCAL aRow := NIL
LOCAL oRow := NIL
LOCAL i
//DAVID: use current row DEFAULT nRow TO 0
IF ! ISNUMBER( nRow )
nRow := ::nCurRow
ENDIF
IF ::nResultHandle != NIL
//DAVID:
::lBof := ( Empty( ::LastRec() ) )
IF nRow < 1 .OR. nRow > ::lastrec() //Out of range
// Equal to Clipper behaviour
nRow := ::lastrec() + 1 //LASTREC()+1
::nCurRow := ::lastrec() + 1
// ::lEof := .T.
ENDIF
IF nRow >= 1 .AND. nRow <= ::nNumRows
// NOTE: row count starts from 0
mysql_data_seek( ::nResultHandle, nRow - 1 )
::nCurRow := nRow
//DAVID: ELSE
//DAVID: use current row ::nCurRow++
ENDIF
//DAVID:
::lEof := ( ::Recno() > ::LastRec() )
::aRow := NIL
IF ::eof()
// Phantom record with empty fields
::aRow := Array( Len( ::aFieldStruct ) )
AFill( ::aRow, "" )
ELSE
::aRow := mysql_fetch_row( ::nResultHandle )
ENDIF
IF ::aRow != NIL
// Convert answer from text field to correct clipper types
FOR i := 1 TO ::nNumFields
SWITCH ::aFieldStruct[ i ][ MYSQL_FS_TYPE ]
CASE MYSQL_TYPE_TINY
//DAVID:
IF ::aRow[ i ] == NIL
::aRow[ i ] := "0"
ENDIF
::aRow[ i ] := Val( ::aRow[ i ] ) != 0
EXIT
CASE MYSQL_TYPE_SHORT
CASE MYSQL_TYPE_LONG
CASE MYSQL_TYPE_LONGLONG
CASE MYSQL_TYPE_INT24
CASE MYSQL_TYPE_NEWDECIMAL
//DAVID:
IF ::aRow[ i ] == NIL
::aRow[ i ] := "0"
ENDIF
::aRow[ i ] := Val( ::aRow[ i ] )
EXIT
CASE MYSQL_TYPE_DOUBLE
CASE MYSQL_TYPE_FLOAT
//DAVID:
IF ::aRow[ i ] == NIL
::aRow[ i ] := "0"
ENDIF
::aRow[ i ] := Val( ::aRow[ i ] )
EXIT
CASE MYSQL_TYPE_DATE
IF Empty( ::aRow[ i ] )
::aRow[ i ] := hb_SToD()
ELSE
// Date format YYYY-MM-DD
::aRow[ i ] := hb_SToD( Left( ::aRow[ i ], 4 ) + SubStr( ::aRow[ i ], 6, 2 ) + Right( ::aRow[ i ], 2 ) )
ENDIF
EXIT
CASE MYSQL_TYPE_BLOB
// Memo field
EXIT
CASE MYSQL_TYPE_STRING
CASE MYSQL_TYPE_VAR_STRING
// char field
EXIT
CASE MYSQL_TYPE_DATETIME
// DateTime field
EXIT
OTHERWISE
//DAVID: Alert( "Unknown type from SQL Server Field: " + hb_NToS( i ) + " is type " + hb_NToS( ::aFieldStruct[ i ][ MYSQL_FS_TYPE ] ) )
// QOUT( "Unknown type from SQL Server Field: " + hb_NToS( i ) + " is type " + hb_NToS( ::aFieldStruct[ i ][ MYSQL_FS_TYPE ] ) )
ENDSWITCH
//DAVID:
IF ::lFieldAsData
__objsetValuelist( Self, { { ::aFieldStruct[ i ][ MYSQL_FS_NAME ], ::aRow[ i ] } } )
ENDIF
NEXT
oRow := TMySQLRow():New( ::aRow, ::aFieldStruct )
ENDIF
ENDIF
//DAVID: IF ::arow == NIL; msginfo( "::arow NIL" ); ENDIF
RETURN iif( ::aRow == NIL, NIL, oRow )
// Free result handle and associated resources
METHOD Destroy() CLASS TMySQLQuery
::nResultHandle := NIL
RETURN Self
METHOD FCount() CLASS TMySQLQuery
RETURN ::nNumFields
METHOD Error() CLASS TMySQLQuery
::lError := .F.
RETURN mysql_error( ::nSocket )
// Given a field name returns it's position
METHOD FieldPos( cFieldName ) CLASS TMySQLQuery
LOCAL cUpperName, nPos
cUpperName := Upper( cFieldName )
//DAVID: nPos := AScan( ::aFieldStruct, {| aItem | iif( Upper( aItem[ MYSQL_FS_NAME ] ) == cUpperName, .T., .F. ) } )
nPos := AScan( ::aFieldStruct, {| aItem | Upper( aItem[ MYSQL_FS_NAME ] ) == cUpperName } )
/*
nPos := 0
DO WHILE ++nPos <= Len( ::aFieldStruct )
IF Upper( ::aFieldStruct[ nPos ][ MYSQL_FS_NAME ] ) == cUpperName
EXIT
ENDIF
ENDDO
// I haven't found field name
IF nPos > Len( ::aFieldStruct )
nPos := 0
ENDIF
*/
RETURN nPos
// Returns name of field N
METHOD FieldName( nNum ) CLASS TMySQLQuery
IF nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
RETURN ::aFieldStruct[ nNum ][ MYSQL_FS_NAME ]
ENDIF
RETURN ""
METHOD FieldGet( cnField ) CLASS TMySQLQuery
LOCAL nNum, Value
IF ISCHARACTER( cnField )
nNum := ::FieldPos( cnField )
ELSE
nNum := cnField
ENDIF
IF nNum > 0 .AND. nNum <= ::nNumfields
//DAVID: Value := __objsendmsg( Self,::aFieldStruct[ nNum ][ MYSQL_FS_NAME ] )
Value := ::aRow[ nNum ]
// Char fields are padded with spaces since a real .dbf field would be
IF ::FieldType( nNum ) == "C"
RETURN PadR( Value,::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ] )
ELSE
RETURN Value
ENDIF
ENDIF
RETURN NIL
METHOD FieldLen( nNum ) CLASS TMySQLQuery
IF nNum >=1 .AND. nNum <= Len( ::aFieldStruct )
RETURN ::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ]
ENDIF
RETURN 0
/*
lFormat: when .T. method returns number of formatted decimal places from mysql table otherwise _SET_DECIMALS.
lFormat is usefull for copying table structure from mysql to dbf
*/
METHOD FieldDec( nNum, lFormat ) CLASS TMySQLQuery
IF ! ISLOGICAL( lFormat )
lFormat := .F.
ENDIF
IF nNum >=1 .AND. nNum <= Len( ::aFieldStruct )
IF !lFormat .AND. ( ::aFieldStruct[ nNum ][ MYSQL_FS_TYPE ] == MYSQL_TYPE_FLOAT .OR. ;
::aFieldStruct[ nNum ][ MYSQL_FS_TYPE ] == MYSQL_TYPE_DOUBLE )
RETURN Set( _SET_DECIMALS )
ELSE
RETURN ::aFieldStruct[ nNum ][ MYSQL_FS_DECIMALS ]
ENDIF
ENDIF
RETURN 0
METHOD FieldType( nNum ) CLASS TMySQLQuery
IF nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
SWITCH ::aFieldStruct[ nNum ][ MYSQL_FS_TYPE ]
CASE MYSQL_TYPE_TINY
RETURN "L"
CASE MYSQL_TYPE_SHORT
CASE MYSQL_TYPE_LONG
CASE MYSQL_TYPE_LONGLONG
CASE MYSQL_TYPE_FLOAT
CASE MYSQL_TYPE_DOUBLE
CASE MYSQL_TYPE_NEWDECIMAL
CASE MYSQL_TYPE_INT24
RETURN "N"
CASE MYSQL_TYPE_VAR_STRING
CASE MYSQL_TYPE_STRING
CASE MYSQL_TYPE_DATETIME
RETURN "C"
CASE MYSQL_TYPE_DATE
RETURN "D"
CASE MYSQL_TYPE_BLOB
CASE MYSQL_TYPE_MEDIUM_BLOB
RETURN "M"
ENDSWITCH
ENDIF
RETURN "U"
Lembrando novamente q se a classe q vc procura for a mesma da contrib todo código fonte esta lá.
[]´s