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