1 
2 #include "pyodbc.h"
3 #include "dbspecific.h"
4 
PrintBytes(void * p,size_t len)5 void PrintBytes(void* p, size_t len)
6 {
7     unsigned char* pch = (unsigned char*)p;
8     for (size_t i = 0; i < len; i++)
9         printf("%02x ", (int)pch[i]);
10     printf("\n");
11 }
12 
13 #define _MAKESTR(n) case n: return #n
SqlTypeName(SQLSMALLINT n)14 const char* SqlTypeName(SQLSMALLINT n)
15 {
16     switch (n)
17     {
18         _MAKESTR(SQL_UNKNOWN_TYPE);
19         _MAKESTR(SQL_CHAR);
20         _MAKESTR(SQL_VARCHAR);
21         _MAKESTR(SQL_LONGVARCHAR);
22         _MAKESTR(SQL_NUMERIC);
23         _MAKESTR(SQL_DECIMAL);
24         _MAKESTR(SQL_INTEGER);
25         _MAKESTR(SQL_SMALLINT);
26         _MAKESTR(SQL_FLOAT);
27         _MAKESTR(SQL_REAL);
28         _MAKESTR(SQL_DOUBLE);
29         _MAKESTR(SQL_DATETIME);
30         _MAKESTR(SQL_WCHAR);
31         _MAKESTR(SQL_WVARCHAR);
32         _MAKESTR(SQL_WLONGVARCHAR);
33         _MAKESTR(SQL_TYPE_DATE);
34         _MAKESTR(SQL_TYPE_TIME);
35         _MAKESTR(SQL_TYPE_TIMESTAMP);
36         _MAKESTR(SQL_SS_TIME2);
37         _MAKESTR(SQL_SS_XML);
38         _MAKESTR(SQL_BINARY);
39         _MAKESTR(SQL_VARBINARY);
40         _MAKESTR(SQL_LONGVARBINARY);
41     }
42     return "unknown";
43 }
44 
CTypeName(SQLSMALLINT n)45 const char* CTypeName(SQLSMALLINT n)
46 {
47     switch (n)
48     {
49         _MAKESTR(SQL_C_CHAR);
50         _MAKESTR(SQL_C_WCHAR);
51         _MAKESTR(SQL_C_LONG);
52         _MAKESTR(SQL_C_SHORT);
53         _MAKESTR(SQL_C_FLOAT);
54         _MAKESTR(SQL_C_DOUBLE);
55         _MAKESTR(SQL_C_NUMERIC);
56         _MAKESTR(SQL_C_DEFAULT);
57         _MAKESTR(SQL_C_DATE);
58         _MAKESTR(SQL_C_TIME);
59         _MAKESTR(SQL_C_TIMESTAMP);
60         _MAKESTR(SQL_C_TYPE_DATE);
61         _MAKESTR(SQL_C_TYPE_TIME);
62         _MAKESTR(SQL_C_TYPE_TIMESTAMP);
63         _MAKESTR(SQL_C_INTERVAL_YEAR);
64         _MAKESTR(SQL_C_INTERVAL_MONTH);
65         _MAKESTR(SQL_C_INTERVAL_DAY);
66         _MAKESTR(SQL_C_INTERVAL_HOUR);
67         _MAKESTR(SQL_C_INTERVAL_MINUTE);
68         _MAKESTR(SQL_C_INTERVAL_SECOND);
69         _MAKESTR(SQL_C_INTERVAL_YEAR_TO_MONTH);
70         _MAKESTR(SQL_C_INTERVAL_DAY_TO_HOUR);
71         _MAKESTR(SQL_C_INTERVAL_DAY_TO_MINUTE);
72         _MAKESTR(SQL_C_INTERVAL_DAY_TO_SECOND);
73         _MAKESTR(SQL_C_INTERVAL_HOUR_TO_MINUTE);
74         _MAKESTR(SQL_C_INTERVAL_HOUR_TO_SECOND);
75         _MAKESTR(SQL_C_INTERVAL_MINUTE_TO_SECOND);
76         _MAKESTR(SQL_C_BINARY);
77         _MAKESTR(SQL_C_BIT);
78         _MAKESTR(SQL_C_SBIGINT);
79         _MAKESTR(SQL_C_UBIGINT);
80         _MAKESTR(SQL_C_TINYINT);
81         _MAKESTR(SQL_C_SLONG);
82         _MAKESTR(SQL_C_SSHORT);
83         _MAKESTR(SQL_C_STINYINT);
84         _MAKESTR(SQL_C_ULONG);
85         _MAKESTR(SQL_C_USHORT);
86         _MAKESTR(SQL_C_UTINYINT);
87         _MAKESTR(SQL_C_GUID);
88     }
89     return "unknown";
90 }
91 
92 
93 #ifdef PYODBC_TRACE
DebugTrace(const char * szFmt,...)94 void DebugTrace(const char* szFmt, ...)
95 {
96     va_list marker;
97     va_start(marker, szFmt);
98     vprintf(szFmt, marker);
99     va_end(marker);
100 }
101 #endif
102 
103 #ifdef PYODBC_LEAK_CHECK
104 
105 // THIS IS NOT THREAD SAFE: This is only designed for the single-threaded unit tests!
106 
107 struct Allocation
108 {
109     const char* filename;
110     int lineno;
111     size_t len;
112     void* pointer;
113     int counter;
114 };
115 
116 static Allocation* allocs = 0;
117 static int bufsize = 0;
118 static int count = 0;
119 static int allocCounter = 0;
120 
_pyodbc_malloc(const char * filename,int lineno,size_t len)121 void* _pyodbc_malloc(const char* filename, int lineno, size_t len)
122 {
123     void* p = malloc(len);
124     if (p == 0)
125         return 0;
126 
127     if (count == bufsize)
128     {
129         allocs = (Allocation*)realloc(allocs, (bufsize + 20) * sizeof(Allocation));
130         if (allocs == 0)
131         {
132             // Yes we just lost the original pointer, but we don't care since everything is about to fail.  This is a
133             // debug leak check, not a production malloc that needs to be robust in low memory.
134             bufsize = 0;
135             count   = 0;
136             return 0;
137         }
138         bufsize += 20;
139     }
140 
141     allocs[count].filename = filename;
142     allocs[count].lineno   = lineno;
143     allocs[count].len      = len;
144     allocs[count].pointer  = p;
145     allocs[count].counter  = allocCounter++;
146 
147     printf("malloc(%d): %s(%d) %d %p\n", allocs[count].counter, filename, lineno, (int)len, p);
148 
149     count += 1;
150 
151     return p;
152 }
153 
pyodbc_free(void * p)154 void pyodbc_free(void* p)
155 {
156     if (p == 0)
157         return;
158 
159     for (int i = 0; i < count; i++)
160     {
161         if (allocs[i].pointer == p)
162         {
163             printf("free(%d): %s(%d) %d %p i=%d\n", allocs[i].counter, allocs[i].filename, allocs[i].lineno, (int)allocs[i].len, allocs[i].pointer, i);
164             memmove(&allocs[i], &allocs[i + 1], sizeof(Allocation) * (count - i - 1));
165             count -= 1;
166             free(p);
167             return;
168         }
169     }
170 
171     printf("FREE FAILED: %p\n", p);
172     free(p);
173 }
174 
pyodbc_leak_check()175 void pyodbc_leak_check()
176 {
177     if (count == 0)
178     {
179         printf("NO LEAKS\n");
180     }
181     else
182     {
183         printf("********************************************************************************\n");
184         printf("%d leaks\n", count);
185         for (int i = 0; i < count; i++)
186             printf("LEAK: %d %s(%d) len=%d\n", allocs[i].counter, allocs[i].filename, allocs[i].lineno, allocs[i].len);
187     }
188 }
189 
190 #endif
191