Lorsque vous appelez la fonction SQLBindParameter dans le pilote Jet ODBC, et que vous liez à un type de données SQL de SQL_NUMERIC ou que vous liez SQL_C_BINARY à SQL_WCHAR, une fuite de mémoire survient.
Si vous utilisez l'Analyseur de performances (PerfMon) pour visualiser le compteur Octets privés pour le processus, vous voyez une augmentation progressive mais constante de la mémoire, et la mémoire n'est pas libérée lorsque les instructions ou les connexions se terminent.
Des tampons sont utilisés au sein du pilote Jet ODBC pour aider à convertir les types de données des paramètres ODBC en types de données natifs pour le moteur de base de données Jet. Il est fait référence à ces tampons par le biais de pointeurs conservés sur le handle d'instruction, au sein des descripteurs de paramètre (IPD).
Normalement, le code vérifie si le pointeur fait déjà référence à un tampon de mémoire valide, puis utilise à nouveau le tampon, s'il existe. Toutefois, lorsque vous liez un type de données SQL_NUMERIC, ou lorsque vous liez SQL_C_BINARY à SQL_WCHAR, de la mémoire nouvelle est allouée et attribuée au pointeur sans vérification préalable, et la valeur précédente est écrasée.
Ce problème a été résolu dans les derniers Service packs de Windows 2000 et MDAC 2.5.
Pour résoudre ce problème, procurez-vous le dernier Service Pack de Windows 2000. Pour plus d'informations, consultez l'article suivant dans la Base de connaissances Microsoft :
Procédures d'obtention du dernier Service Pack de Windows 2000
Pour résoudre ce problème, procurez-vous le dernier Service pack de Microsoft Data Access Components 2.5. Pour plus d'informations, consultez l'article suivant dans la Base de connaissances Microsoft :
INFO : Obtention du dernier Service Pack de MDAC 2.5
La version anglaise de ce correctif doit disposer des attributs de fichier suivants ou de ceux d'une version ultérieure :
Date Version Taille Nom de fichier
----------------------------------------------------
13.09.00 4.0.5708.0 270.608 octets Odbcjt32.dll
14.09.00 1.10.101.0 295.696 octets Q273772_W2K_SP2_x86_en.EXE
REMARQUE : Ce correctif requiert Microsoft Data Access Components (MDAC) 2.5 Service Pack 1 (SP1) ou une version ultérieure en raison des dépendances sur les autres fichiers introduits à l'aide de MDAC 2.5 SP1. Aucun correctif n'est disponible que vous pouvez appliquer directement à MDAC 2.5.
Pour installer ce correctif sur une plate-forme Microsoft Windows 2000, exécutez le lot d'installation du correctif (Q273772_W2K_SP2_x86_en.EXE). Bien que le correctif lui-même ne dépende pas de la plate-forme, le lot d'installation du correctif a été conçu pour s'exécuter uniquement sur les plates-formes Windows 2000, et ne s'exécutera pas sur les plates-formes Microsoft Windows NT 4.0, Microsoft Windows 95, ni Microsoft Windows 98. MDAC contient des fichiers système protégés que vous pouvez remplacer uniquement par un installateur de correctif signé numériquement sous Windows 2000. Le fichier de correctif indépendant est fourni également pour que vous puissiez copier ce fichier directement sur les plates-formes Windows NT 4.0, Windows 95 ou Windows 98.
Microsoft a confirmé l'existence de ce problème dans les produits Microsoft répertoriés au début de cet article.
Ce problème a été corrigé pour la première fois dans Microsoft Data Access Components 2.5 Service Pack 2 et dans Microsoft Windows 2000 Service Pack 2.
Si vous examinez de manière périodique la mémoire dédiée au processus au cours de l'exécution du processus, vous pouvez voir un nombre croissant de 0x100000 (1048576) allocations d'octets. Si l'exécution du processus se poursuit, un dépassement de mémoire peut avoir lieu, entraînant le blocage (pas de réponse) ou l'échec du processus.
Procédure à suivre pour reproduire ce comportement
Copiez le code suivant dans une application de console Microsoft Visual C++, puis compilez le code. Notez que vous pouvez avoir à changer le nom de la source de données, ainsi que l'ID et le mot de passe d'utilisateur.
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <tchar.h>
#include <stdlib.h>
#include <stdio.h>
#define LEAK_NUMERIC 1 //Uiliser cela pour déterminer une fuite de données NUMERIC ou BINARY
void HandleError(SQLHANDLE hHandle, SQLSMALLINT hType, RETCODE RetCode)
{
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
TCHAR szMessage[1000];
TCHAR szState[SQL_SQLSTATE_SIZE];
if (RetCode == SQL_INVALID_HANDLE)
{
fprintf(stderr,"Handle non valide !\n");
return;
}
while (SQLGetDiagRec(hType,
hHandle,
++iRec,
(SQLCHAR *)szState,
&iError,
(SQLCHAR *)szMessage,
(SQLSMALLINT)(sizeof(szMessage) / sizeof(TCHAR)),
(SQLSMALLINT *)NULL) == SQL_SUCCESS)
{
fprintf(stderr,TEXT("[%5.5s] %s (%d)\n"),szState,szMessage,iError);
}
}
char* szConnStringIn = "Driver={Microsoft Access Driver (*.mdb)};DBQ=E:\\JetLeak\\TestDatabase.mdb";
char* szDropTable = "DROP TABLE LeakTable";
//char* szInsertStatement = "INSERT INTO LeakTable VALUES (?)";
char* szSelectStatement = "SELECT * FROM LeakTable WHERE val1 = ?";
const int nParamCount = 1;
#if LEAK_NUMERIC
char* szCreateTable = "CREATE TABLE LeakTable (val1 long)";
#else
char* szCreateTable = "CREATE TABLE LeakTable (val1 varchar(10))";
#endif
void main(int argc, char* argv[])
{
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN nstatus;
char szConnStringOut[1024];
SQLSMALLINT cbConnOut;
SQLINTEGER status[nParamCount];
#if LEAK_NUMERIC
SQLCHAR szParam[nParamCount][10] = {"12345"};
#else
BYTE szParam[nParamCount][10] = {0x31,0x33,0x34,0x39};
#endif
//Pas de vérification des codes de renvoi dans certains cas par soucis de
clarté.
nstatus = SQLAllocHandle(SQL_HANDLE_ENV,NULL,&henv);
nstatus = SQLSetEnvAttr(henv,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)
SQL_OV_ODBC3,0);
nstatus = SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc);
nstatus = SQLDriverConnect(hdbc,
NULL,
(SQLCHAR*) szConnStringIn,
SQL_NTS,
(SQLCHAR*) szConnStringOut,
sizeof (szConnStringOut),
&cbConnOut,
SQL_DRIVER_COMPLETE);
if (nstatus != SQL_SUCCESS && nstatus != SQL_SUCCESS_WITH_INFO)
{
HandleError(hdbc,SQL_HANDLE_DBC,nstatus);
return;
}
nstatus = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szDropTable, SQL_NTS);
nstatus = SQLExecDirect(hstmt, (SQLCHAR*) szCreateTable, SQL_NTS);
if (!SQL_SUCCEEDED(nstatus))
{
HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
}
int i;
//un seul paramètre dans ce cas
for (i=0; i < nParamCount; i++)
{
status[i] = SQL_NTS;
#if LEAK_NUMERIC
nstatus = SQLBindParameter(hstmt,
i+1,
SQL_PARAM_INPUT,
SQL_C_CHAR,
SQL_NUMERIC,
10,
0,
szParam[i],
10,
&status[i]);
#else
nstatus = SQLBindParameter(hstmt,
i+1,
SQL_PARAM_INPUT,
SQL_C_BINARY,
SQL_WCHAR,
10,
0,
szParam[i],
10,
&status[i]);
#endif
}
nstatus = SQLPrepare(hstmt,(SQLCHAR*) szSelectStatement, SQL_NTS);
if (nstatus != SQL_SUCCESS)
{
HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
}
for (i=0; i < 100000; i++)
{
if (i % 100 == 0)
{
printf("Heures %d sélectionnées\n", i);
//printf("Enregistrements %d insérés\n", i);
Sleep(100);
}
nstatus = SQLExecute(hstmt);
if (nstatus != SQL_SUCCESS)
{
HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
}
SQLFreeStmt(hstmt, SQL_CLOSE);
}
nstatus = SQLExecDirect(hstmt, (SQLCHAR*) "DELETE FROM LeakTable",
SQL_NTS);
if (nstatus != SQL_SUCCESS)
{
HandleError(hstmt,SQL_HANDLE_STMT,nstatus);
}
SQLFreeStmt(hstmt, SQL_CLOSE);
SQLDisconnect(hdbc);
}
REMARQUE : Vous pouvez utiliser la constante LEAK_NUMERIC pour démontrer la fuite SQL_NUMERIC ou SQL_C_BINARY.
Créez une nouvelle base de données Microsoft Access vide comme spécifié par l'emplacement dans votre chaîne de connexion.
Commencez l'exécution du code, puis utilisez l'Analyseur de performances pour surveiller le compteur Octets privés pour le processus.
Notez que le compteur Octets privés augmente de manière constante au fil de l'exécution du code.
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.
Merci ! Vos commentaires sont très utiles pour l'amélioration de notre contenu d'aide et de support. Si vous avez besoin d'aide complémentaire, veuillez consulter la page d'accueil d'aide et support.