The real problem is when we need to pass NULL value to a parameter of a ServerSide procedure or function.
For example, this is a function stored on the MSSQL server.
- Code: Select all Expand view
CREATE FUNCTION nulltest( @nVar Int )
RETURNING Int
AS
BEGIN
DECLARE @RetVal Int
IF @nVar Is Null
@RetVal = -1
ELSE
@RetVal = 2 * @nVar
RETURN @RetVal
END
When an Integer is passed as parameter, this function returns twice the parameter; when NULL is passed, it returns -1 and when a value of any other datatype is passed the server complains data type mismatch.
Here is the xHarbour implementation of calling this function and retrieving the return value.
- Code: Select all Expand view
Function Main()
local oCn, oCmd, oParam
local cConStr := <our connection string to mssql server>
oCn := TOleAuto():new( "ADODB.Connection" )
with object oCn
:ConnectionString := cConStr
:Open()
end
oCn:CursorLocation := adUseClient
oCmd := TOleAuto():New( 'ADODB.Command' )
with object oCmd
:ActiveConnection := oCn
:CommandText := 'nulltest'
:CommandType := adCmdStoredProc
:Prepared := .t.
end
oParam := oCmd:CreateParameter( 'retval', adInteger, adParamReturnValue )
oCmd:Parameters:Append( oParam )
oParam := oCmd:CreateParameter( 'nval', adInteger, adParamInput )
oCmd:Parameters:Append( oParam )
MsgInfo( ExecCmd( oCmd, 10 ) ) // result 20 : Correct
MsgInfo( ExecCmd( oCmd, VTWrapper( 1, nil ) ) ) // result -1 : Correct
MsgInfo( ExecCmd( oCmd, nil ) ) // should result in -1 but generates error
oCn:Close()
return nil
//--------------------------------------------------------------//
static function ExecCmd( oCmd, uInput )
local nRet
oCmd:Parameters( 1 ):Value := uInput
TRY
oCmd:Execute()
nRet := oCmd:Parameters( 0 ):Value
CATCH
ShowAdoError( oCmd:ActiveConnection )
END
return nRet
//--------------------------------------------------------------//
static function ShowAdoError( oCon )
local oErr, nErr, cErr
nErr := oCon:Errors:Count()
if nErr > 0
oErr := oCon:Errors[ nErr - 1 ]
cErr := "Description : " + oErr:Description
cErr += CRLF + "SubCode : " + cValToChar( oErr:NativeError )
cErr += CRLF + "Source : " + oErr:Source
MsgInfo( cErr )
else
MsgInfo( 'No Ado Error' )
endif
return nil
//---------------------------------------------------------------//
It can be seen that only when we pass VTWrapper( 1, nil ), the parameter value is passed as NULL and when NIL is not taken as NULL and runtime error occurs.
Procedure ‘nulltest’ expects parameter @nVar which was not supplied.
The modification I made to win32ole.prg line 904 is :
Instead of
- Code: Select all Expand view
//pVariant->n1.n2.vt = VT_EMPTY;
Substituted
- Code: Select all Expand view
pVariant->n1.n2.vt = VT_NULL;
With the patch I suggested above, assigning NIL to a parameter value is passed on as NULL to the background function or procedure.