Extended Stored Procedure: is there a small memory leak in srv_paraminfo??

From: Daniel (softwareengineer98037_at_yahoo.com)
Date: 07/31/04

  • Next message: David: "Access , ODBC and windows 98"
    Date: Fri, 30 Jul 2004 19:42:44 -0700
    
    

    I called my own extended stored procedure 1000 times to make sure there was
    no memory leak but the sqlservr.exe memory usage went up so i thought there
    might be a memory leak. I commented out all the code in the extended stored
    procedure but the call to srv_paraminfo and it seems that srv_paraminfo,
    when called w/ null to get parameter lenght etc. leaks some memory. perhaps
    something in the internals of srv_paraminfo. If an extended stored procedure
    is called every 10 milliseconds for 24 hours and all it does is use
    srv_paraminfo to get the size of the incoming parameter but never takes the
    parameter, the sqlservr.exe memory usage will increase by about 30 megabytes
    a day. This worrys me, will i have to restart sql server 2000 now and then
    if i use srv_paraminfo in a stored procedure that is called frequently? I
    thought maybe it was just somethign wrong w/ MY code, so i ran the sane test
    w/ a sample extended stored procedure that comes on the SQL Server 2000 CD
    called: xp_srv_paraminfo_sample and the memory climbed at the same rate. It
    doesnt seem to matter what i send into an extended stored procedure or how
    large it is, just seems that when ever srv_paraminfo is used to get the size
    of data, it leaks memory.

    Here is the sample on the SQL server 2000 CD that seems to leak about 30
    megabytes a day if run every 10 milliseconds for 24 hours:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odssql/ods_6_sam_01_4yel.asp

    Here is the code in the sample extended stored procedure on the SQL Server
    2000 CD:

    /***********************************************************************
    Copyright (c) 2000, Microsoft Corporation
    All Rights Reserved.
    ***********************************************************************/
    // This is an example of an extended procedure DLL built with Open Data
    // Services. The function within the DLL can be invoked by using the
    // extended stored procedures support in SQL Server.
    //
    // For more information on Open Data Services refer to the Microsoft Open
    // Data Services Programmer's Reference.
    //
    // xp_srv_paraminfo_sample accepts parameters from a Transact-SQL statement.
    // It analyzes each parameter then posts a result set to the client
    // containing information about each parameter and the parameter's value.
    //
    // The Transact-SQL script xp_param.sql installs and exercises the extended
    // stored procedure.
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <windows.h>
    #include <srv.h>
    #include <time.h>

    // Macros -- return codes
    #define XP_NOERROR 0
    #define XP_ERROR 1

    #define MAX_SERVER_ERROR 20000
    #define XP_PARAM_ERROR MAX_SERVER_ERROR+1

    void printError (SRV_PROC *pSrvProc, CHAR* szErrorMsg);
    void printUsage (SRV_PROC *pSrvProc);

    // It is highly recommended that all Microsoft® SQL Server (7.0
    // and greater) extended stored procedure DLLs implement and export
    // __GetXpVersion. For more information see SQL Server
    // Books Online
    ULONG __GetXpVersion()

    {
        return ODS_VERSION;
    }

    SRVRETCODE xp_srv_paraminfo_sample
        (
        SRV_PROC* pSrvProc
        )
        {
        char acHeader[24];
        BYTE bType;
        long cbMaxLen;
        long cbActualLen;
        PBYTE* ppbData;
        BOOL fNull;
        int nParams;
        int nParam;
        SRVRETCODE rc = XP_NOERROR;

    #ifdef _DEBUG
        // In a debug build, look up the data type name for assistance.
        DBCHAR* pdbcDataType;
        int cbDataType;
    #endif

        // Count up the number of input parameters
        nParams = srv_rpcparams(pSrvProc);
        if (nParams == -1)
            {
            printUsage (pSrvProc);
            return (XP_ERROR);
            }

        // Build an array of data pointers for the input parameters.
        ppbData = (PBYTE*) malloc(nParams * sizeof(PBYTE));
        if (ppbData == NULL)
            {
            printError (pSrvProc, "Memory allocation error.");
            return (XP_ERROR);
            }
        memset(ppbData, (int) NULL, nParams * sizeof(PBYTE));

        for (nParam = 0; nParam < nParams; nParam++)
            {
            // Use srv_paraminfo to get data type and length information. Ask
            // for the data later using a non-null ppbData argument in a second
            // srv_paraminfo call.
            if (srv_paraminfo(pSrvProc, nParam+1, &bType, &cbMaxLen,
    &cbActualLen,
                NULL, &fNull) == FAIL)
                {
                rc = XP_ERROR;
                break;
                }

            // Describe the paramter. The column header indicates whether
            // the parameter is input or output.
            sprintf(acHeader, "Parameter %d: %s", nParam+1,
             ((srv_paramstatus(pSrvProc, nParam+1) & SRV_PARAMRETURN) ?
                "Output" : "Input"));
            srv_describe(pSrvProc, nParam+1, acHeader, SRV_NULLTERM, bType,
                cbActualLen, bType, cbActualLen, NULL);

            // If there's data, then dynamically allocate memory and retrieve
    it.
            if (fNull == 0)
                {
                ppbData[nParam] = malloc(cbActualLen);
                if (ppbData[nParam] == NULL)
                    {
                    rc = XP_ERROR;
                    break;
                    }

                if (srv_paraminfo(pSrvProc, nParam+1, &bType, &cbMaxLen,
                    &cbActualLen, ppbData[nParam], &fNull) == FAIL)
                    {
                    rc = XP_ERROR;
                    break;
                    }
                }

    #ifdef _DEBUG
            // A debugging aid. Get the name of the data type of the parameter.
            pdbcDataType = srv_symbol(SRV_DATATYPE, (int) bType, &cbDataType);
    #endif

            // Set the column's data;
            if (srv_setcoldata(pSrvProc, nParam+1, ppbData[nParam]) == FAIL)
                {
                rc = XP_ERROR;
                break;
                }
            }

        // Send the row to the client.
        if (rc == XP_NOERROR)
            {
            if (srv_sendrow(pSrvProc) == FAIL)
                {
                rc = XP_ERROR;
                }
            }

        // Free dynamically allocated memory.
        for (nParam = 0; nParam < nParams; nParam++)
            {
            if (ppbData[nParam])
                {
                free(ppbData[nParam]);
                }
            }

        free(ppbData);

        // Indicate that we're done.
        if (rc == XP_NOERROR)
            {
            srv_senddone(pSrvProc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, 1);
            }
        else if (rc == XP_ERROR)
            {
            printError (pSrvProc, "XP encountered an error.");
            }

        return (rc);
        }

    // send szErrorMsg to client
    void printError (SRV_PROC *pSrvProc, CHAR* szErrorMsg)
        {
        srv_sendmsg(pSrvProc, SRV_MSG_ERROR, XP_ERROR, SRV_INFO, 1,
                NULL, 0, (DBUSMALLINT) __LINE__,
                szErrorMsg,
                SRV_NULLTERM);

        srv_senddone(pSrvProc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
        }

    // send XP usage info to client
    void printUsage (SRV_PROC *pSrvProc)
        {
        // usage: exec xp_srv_paraminfo_sample [@param1, [@param2 output],...]

        srv_sendmsg(pSrvProc, SRV_MSG_ERROR, XP_PARAM_ERROR, SRV_INFO, 1,
                NULL, 0, (DBUSMALLINT) __LINE__,
                "usage: exec xp_srv_paraminfo_sample [@param1, [@param2
    output],...]",
                SRV_NULLTERM);
        srv_senddone(pSrvProc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);

        }


  • Next message: David: "Access , ODBC and windows 98"

    Relevant Pages

    • Re: There seems to be a memory leak in srv_paraminfo
      ... > no memory leak but the sqlservr.exe memory usage went up so i thought ... will i have to restart sql server 2000 now and then ... > w/ a sample extended stored procedure that comes on the SQL Server 2000 CD ...
      (microsoft.public.sqlserver.programming)
    • There seems to be a memory leak in srv_paraminfo
      ... I called my own extended stored procedure 1000 times to make sure there was ... no memory leak but the sqlservr.exe memory usage went up so i thought there ... might be a memory leak. ... w/ a sample extended stored procedure that comes on the SQL Server 2000 CD ...
      (microsoft.public.sqlserver.programming)
    • Re: There seems to be a memory leak in srv_paraminfo
      ... Unlike the case for some other applications, memory once allocated to ... SQL Server remains allocated to sqlservr.exe, but if it's not in use, it ... >no memory leak but the sqlservr.exe memory usage went up so i thought there ... >w/ a sample extended stored procedure that comes on the SQL Server 2000 CD ...
      (microsoft.public.sqlserver.programming)
    • Re: Extended Stored Procedure: Loopback connection
      ... SQL Server ships a sample exactly showing this: ... SQLRETURN sret, ... SRV_PROC* srvproc); ... NULL, 0, 0, "Error executing extended stored procedure: ...
      (microsoft.public.sqlserver.odbc)
    • Re: Track memory leak
      ... Inside SQL Server 2000's Memory Management Facilities ... I also recommend Inside SQL Server 2000 and SQL Server 2000 Performance ... > effectively or not and also how can i track for any memory leak if any.. ... > Should I just wait for some errors to show up in the error log to ...
      (microsoft.public.sqlserver.server)

    Loading