1 
2 /*
3  * util.c
4  *   Utility functions.
5  *
6  * Copyright (c) 2011 eSilo, LLC. All rights reserved.
7  * This is free software; see the source for copying conditions.  There is
8  * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
9  * PURPOSE.
10  */
11 
12 #include "libpqtypes-int.h"
13 
14 PGresult *
pqt_copyresult(PGtypeArgs * args,int nattrs)15 pqt_copyresult(PGtypeArgs *args, int nattrs)
16 {
17 	int i;
18 	PGresult *res;
19 	int tableid, columnid, format;
20 	PGresAttDesc *ad = (PGresAttDesc *) malloc(nattrs * sizeof(PGresAttDesc));
21 
22 	if (!ad)
23 	{
24 		PQseterror(PQT_OUTOFMEMORY);
25 		return NULL;
26 	}
27 
28 	tableid  = PQftable(args->get.result, args->get.field_num);
29 	columnid = PQftablecol(args->get.result, args->get.field_num);
30 	format   = PQfformat(args->get.result, args->get.field_num);
31 
32 	for (i=0; i < nattrs; i++)
33 	{
34 		ad[i].tableid  = tableid;
35 		ad[i].columnid = columnid;
36 		ad[i].format   = format;
37 
38 		/* simple array */
39 		if (args->typhandler->nattrs == 0)
40 		{
41 			ad[i].typid     = args->typhandler->typoid;
42 			ad[i].typlen    = args->typhandler->typlen;
43 			ad[i].name      = NULL;
44 			ad[i].atttypmod = -1;
45 		}
46 		/* composite/record */
47 		else
48 		{
49 			ad[i].typid     = args->typhandler->attDescs[i].attoid;
50 			ad[i].typlen    = args->typhandler->attDescs[i].attlen;
51 			ad[i].name      = args->typhandler->attDescs[i].attname;
52 			ad[i].atttypmod = args->typhandler->attDescs[i].atttypmod;
53 		}
54 	}
55 
56 	res = PQcopyResult(args->get.result,
57 		PG_COPYRES_EVENTS | PG_COPYRES_NOTICEHOOKS);
58 
59 	if (!res)
60 	{
61 		free(ad);
62 		PQseterror(PQT_OUTOFMEMORY);
63 		return NULL;
64 	}
65 
66 	if (!PQsetResultAttrs(res, nattrs, ad))
67 	{
68 		PQclear(res);
69 		PQseterror(PQT_OUTOFMEMORY);
70 		res = NULL;
71 	}
72 
73 	free(ad);
74 	return res;
75 }
76 
77 #ifdef STRICT_MEMORY_ALIGNMENT
78 short
pqt_buf_getint2(char * buffer)79 pqt_buf_getint2(char *buffer)
80 {
81 	short n;
82 	memcpy(&n, buffer, 2);
83 	return (short) ntohs(n);
84 }
85 
86 int
pqt_buf_getint4(char * buffer)87 pqt_buf_getint4(char *buffer)
88 {
89 	int n;
90 	memcpy(&n, buffer, 4);
91 	return (int) ntohl(n);
92 }
93 #endif
94 
95 void
pqt_swap8(void * outp,void * inp,int tonet)96 pqt_swap8(void *outp, void *inp, int tonet)
97 {
98 	static int n = 1;
99 
100 #ifdef STRICT_MEMORY_ALIGNMENT
101 	unsigned int in[2];
102 	unsigned int out[2];
103 	memcpy(&in, inp, 8);
104 #else
105 	unsigned int *in = (unsigned int *) inp;
106 	unsigned int *out = (unsigned int *) outp;
107 #endif
108 
109 	/* swap when needed */
110 	if (*(char *)&n == 1)
111 	{
112 		out[0] = (unsigned int) (tonet ? htonl(in[1]) : ntohl(in[1]));
113 		out[1] = (unsigned int) (tonet ? htonl(in[0]) : ntohl(in[0]));
114 	}
115 	else
116 	{
117 		out[0] = in[0];
118 		out[1] = in[1];
119 	}
120 
121 #ifdef STRICT_MEMORY_ALIGNMENT
122 	memcpy(outp, out, 8);
123 #endif
124 }
125 
126 int
pqt_text_to_int8(char * val,void * out)127 pqt_text_to_int8(char *val, void *out)
128 {
129 	PGint8 n;
130 
131 	/* NOTE: port version of strtoll in port.c. */
132 	errno = 0;
133 	if ((n = (PGint8) strtoll(val, NULL, 10)) == 0 && errno)
134 		return -1;
135 
136 	*(PGint8 *) out = n;
137 	return 0;
138 }
139 
140 int
pqt_text_to_float8(double * f8,char * text,char ** endptr)141 pqt_text_to_float8(double *f8, char *text, char **endptr)
142 {
143 	double d;
144 
145 	errno = 0;
146 	if ((d = strtod(text, endptr)) == 0 && errno)
147 		return 0;
148 
149 	*f8 = d;
150 	return 1;
151 }
152 
153 /* Checks buffer and truncates 'src' if 'dest' is too small. */
154 char *
pqt_strcpy(char * dest,size_t size,const char * src)155 pqt_strcpy(char *dest, size_t size, const char *src)
156 {
157 	size_t src_len = strlen(src);
158 
159 	/* truncate if needed */
160 	if (src_len >= size)
161 		src_len = size - 1;
162 
163 	memcpy(dest, src, src_len);
164 	dest[src_len] = 0;
165 	return dest;
166 }
167 
168 
169 /* ---------------------------
170  * Everything below was taken from postgresql project
171  * A couple of changes here and there.
172  */
173 
174 #ifndef HIGHBIT
175 #	define HIGHBIT (0x80)
176 #endif
177 
178 #ifndef IS_HIGHBIT_SET
179 #	define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT)
180 #endif
181 
182 /*
183  * Fold a character to lower case.
184  *
185  * Unlike some versions of tolower(), this is safe to apply to characters
186  * that aren't upper case letters.  Note however that the whole thing is
187  * a bit bogus for multibyte character sets.
188  */
189 unsigned char
pqt_tolower(unsigned char ch)190 pqt_tolower(unsigned char ch)
191 {
192 	if (ch >= 'A' && ch <= 'Z')
193 		ch += 'a' - 'A';
194 	else if (IS_HIGHBIT_SET(ch) && isupper(ch))
195 		ch = (unsigned char) tolower(ch);
196 	return ch;
197 }
198 
199 /*
200  * Case-independent comparison of two null-terminated strings.
201  */
202 int
pqt_strcasecmp(const char * s1,const char * s2)203 pqt_strcasecmp(const char *s1, const char *s2)
204 {
205 	for (;;)
206 	{
207 		unsigned char ch1 = (unsigned char) *s1++;
208 		unsigned char ch2 = (unsigned char) *s2++;
209 
210 		if (ch1 != ch2)
211 		{
212 			if (ch1 >= 'A' && ch1 <= 'Z')
213 				ch1 += 'a' - 'A';
214 			else if (IS_HIGHBIT_SET(ch1) && isupper(ch1))
215 				ch1 = (unsigned char)tolower(ch1);
216 
217 			if (ch2 >= 'A' && ch2 <= 'Z')
218 				ch2 += 'a' - 'A';
219 			else if (IS_HIGHBIT_SET(ch2) && isupper(ch2))
220 				ch2 = (unsigned char)tolower(ch2);
221 
222 			if (ch1 != ch2)
223 				return (int) ch1 - (int) ch2;
224 		}
225 		if (ch1 == 0)
226 			break;
227 	}
228 	return 0;
229 }
230 
231 /*
232  * Case-independent comparison of two not-necessarily-null-terminated
233  * strings. At most n bytes will be examined from each string.
234  */
235 int
pqt_strncasecmp(const char * s1,const char * s2,size_t n)236 pqt_strncasecmp(const char *s1, const char *s2, size_t n)
237 {
238 	while (n-- > 0)
239 	{
240 		unsigned char ch1 = (unsigned char) *s1++;
241 		unsigned char ch2 = (unsigned char) *s2++;
242 
243 		if (ch1 != ch2)
244 		{
245 			if (ch1 >= 'A' && ch1 <= 'Z')
246 				ch1 += 'a' - 'A';
247 			else if (IS_HIGHBIT_SET(ch1) && isupper(ch1))
248 				ch1 = (unsigned char)tolower(ch1);
249 
250 			if (ch2 >= 'A' && ch2 <= 'Z')
251 				ch2 += 'a' - 'A';
252 			else if (IS_HIGHBIT_SET(ch2) && isupper(ch2))
253 				ch2 = (unsigned char)tolower(ch2);
254 
255 			if (ch1 != ch2)
256 				return (int) ch1 - (int) ch2;
257 		}
258 		if (ch1 == 0)
259 			break;
260 	}
261 	return 0;
262 }
263 
264 
265 
266