PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
mac.c
Go to the documentation of this file.
1 /*
2  * PostgreSQL type definitions for MAC addresses.
3  *
4  * src/backend/utils/adt/mac.c
5  */
6 
7 #include "postgres.h"
8 
9 #include "access/hash.h"
10 #include "libpq/pqformat.h"
11 #include "utils/builtins.h"
12 #include "utils/inet.h"
13 
14 
15 /*
16  * Utility macros used for sorting and comparing:
17  */
18 
19 #define hibits(addr) \
20  ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
21 
22 #define lobits(addr) \
23  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
24 
25 /*
26  * MAC address reader. Accepts several common notations.
27  */
28 
29 Datum
31 {
32  char *str = PG_GETARG_CSTRING(0);
33  macaddr *result;
34  int a,
35  b,
36  c,
37  d,
38  e,
39  f;
40  char junk[2];
41  int count;
42 
43  /* %1s matches iff there is trailing non-whitespace garbage */
44 
45  count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
46  &a, &b, &c, &d, &e, &f, junk);
47  if (count != 6)
48  count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
49  &a, &b, &c, &d, &e, &f, junk);
50  if (count != 6)
51  count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
52  &a, &b, &c, &d, &e, &f, junk);
53  if (count != 6)
54  count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
55  &a, &b, &c, &d, &e, &f, junk);
56  if (count != 6)
57  count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
58  &a, &b, &c, &d, &e, &f, junk);
59  if (count != 6)
60  count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
61  &a, &b, &c, &d, &e, &f, junk);
62  if (count != 6)
63  count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
64  &a, &b, &c, &d, &e, &f, junk);
65  if (count != 6)
66  ereport(ERROR,
67  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
68  errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
69  str)));
70 
71  if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
72  (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
73  (e < 0) || (e > 255) || (f < 0) || (f > 255))
74  ereport(ERROR,
75  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
76  errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
77 
78  result = (macaddr *) palloc(sizeof(macaddr));
79 
80  result->a = a;
81  result->b = b;
82  result->c = c;
83  result->d = d;
84  result->e = e;
85  result->f = f;
86 
87  PG_RETURN_MACADDR_P(result);
88 }
89 
90 /*
91  * MAC address output function. Fixed format.
92  */
93 
94 Datum
96 {
97  macaddr *addr = PG_GETARG_MACADDR_P(0);
98  char *result;
99 
100  result = (char *) palloc(32);
101 
102  snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
103  addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
104 
105  PG_RETURN_CSTRING(result);
106 }
107 
108 /*
109  * macaddr_recv - converts external binary format to macaddr
110  *
111  * The external representation is just the six bytes, MSB first.
112  */
113 Datum
115 {
117  macaddr *addr;
118 
119  addr = (macaddr *) palloc(sizeof(macaddr));
120 
121  addr->a = pq_getmsgbyte(buf);
122  addr->b = pq_getmsgbyte(buf);
123  addr->c = pq_getmsgbyte(buf);
124  addr->d = pq_getmsgbyte(buf);
125  addr->e = pq_getmsgbyte(buf);
126  addr->f = pq_getmsgbyte(buf);
127 
128  PG_RETURN_MACADDR_P(addr);
129 }
130 
131 /*
132  * macaddr_send - converts macaddr to binary format
133  */
134 Datum
136 {
137  macaddr *addr = PG_GETARG_MACADDR_P(0);
139 
140  pq_begintypsend(&buf);
141  pq_sendbyte(&buf, addr->a);
142  pq_sendbyte(&buf, addr->b);
143  pq_sendbyte(&buf, addr->c);
144  pq_sendbyte(&buf, addr->d);
145  pq_sendbyte(&buf, addr->e);
146  pq_sendbyte(&buf, addr->f);
148 }
149 
150 
151 /*
152  * Comparison function for sorting:
153  */
154 
155 static int32
157 {
158  if (hibits(a1) < hibits(a2))
159  return -1;
160  else if (hibits(a1) > hibits(a2))
161  return 1;
162  else if (lobits(a1) < lobits(a2))
163  return -1;
164  else if (lobits(a1) > lobits(a2))
165  return 1;
166  else
167  return 0;
168 }
169 
170 Datum
172 {
175 
177 }
178 
179 /*
180  * Boolean comparisons.
181  */
182 
183 Datum
185 {
188 
190 }
191 
192 Datum
194 {
197 
198  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
199 }
200 
201 Datum
203 {
206 
207  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
208 }
209 
210 Datum
212 {
215 
216  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
217 }
218 
219 Datum
221 {
224 
226 }
227 
228 Datum
230 {
233 
234  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
235 }
236 
237 /*
238  * Support function for hash indexes on macaddr.
239  */
240 Datum
242 {
243  macaddr *key = PG_GETARG_MACADDR_P(0);
244 
245  return hash_any((unsigned char *) key, sizeof(macaddr));
246 }
247 
248 /*
249  * Arithmetic functions: bitwise NOT, AND, OR.
250  */
251 Datum
253 {
254  macaddr *addr = PG_GETARG_MACADDR_P(0);
255  macaddr *result;
256 
257  result = (macaddr *) palloc(sizeof(macaddr));
258  result->a = ~addr->a;
259  result->b = ~addr->b;
260  result->c = ~addr->c;
261  result->d = ~addr->d;
262  result->e = ~addr->e;
263  result->f = ~addr->f;
264  PG_RETURN_MACADDR_P(result);
265 }
266 
267 Datum
269 {
270  macaddr *addr1 = PG_GETARG_MACADDR_P(0);
271  macaddr *addr2 = PG_GETARG_MACADDR_P(1);
272  macaddr *result;
273 
274  result = (macaddr *) palloc(sizeof(macaddr));
275  result->a = addr1->a & addr2->a;
276  result->b = addr1->b & addr2->b;
277  result->c = addr1->c & addr2->c;
278  result->d = addr1->d & addr2->d;
279  result->e = addr1->e & addr2->e;
280  result->f = addr1->f & addr2->f;
281  PG_RETURN_MACADDR_P(result);
282 }
283 
284 Datum
286 {
287  macaddr *addr1 = PG_GETARG_MACADDR_P(0);
288  macaddr *addr2 = PG_GETARG_MACADDR_P(1);
289  macaddr *result;
290 
291  result = (macaddr *) palloc(sizeof(macaddr));
292  result->a = addr1->a | addr2->a;
293  result->b = addr1->b | addr2->b;
294  result->c = addr1->c | addr2->c;
295  result->d = addr1->d | addr2->d;
296  result->e = addr1->e | addr2->e;
297  result->f = addr1->f | addr2->f;
298  PG_RETURN_MACADDR_P(result);
299 }
300 
301 /*
302  * Truncation function to allow comparing mac manufacturers.
303  * From suggestion by Alex Pilosov <alex@pilosoft.com>
304  */
305 Datum
307 {
308  macaddr *addr = PG_GETARG_MACADDR_P(0);
309  macaddr *result;
310 
311  result = (macaddr *) palloc(sizeof(macaddr));
312 
313  result->a = addr->a;
314  result->b = addr->b;
315  result->c = addr->c;
316  result->d = 0;
317  result->e = 0;
318  result->f = 0;
319 
320  PG_RETURN_MACADDR_P(result);
321 }
void pq_sendbyte(StringInfo buf, int byt)
Definition: pqformat.c:105
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:359
unsigned char f
Definition: inet.h:101
StringInfoData * StringInfo
Definition: stringinfo.h:46
Datum hashmacaddr(PG_FUNCTION_ARGS)
Definition: mac.c:241
#define PG_RETURN_INT32(x)
Definition: fmgr.h:298
Datum macaddr_le(PG_FUNCTION_ARGS)
Definition: mac.c:193
Datum macaddr_ge(PG_FUNCTION_ARGS)
Definition: mac.c:211
int errcode(int sqlerrcode)
Definition: elog.c:575
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:232
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:313
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:379
signed int int32
Definition: c.h:253
#define hibits(addr)
Definition: mac.c:19
#define PG_RETURN_MACADDR_P(x)
Definition: inet.h:117
unsigned char c
Definition: inet.h:98
#define ERROR
Definition: elog.h:43
unsigned char a
Definition: inet.h:96
#define PG_GETARG_MACADDR_P(n)
Definition: inet.h:116
#define lobits(addr)
Definition: mac.c:22
Datum macaddr_lt(PG_FUNCTION_ARGS)
Definition: mac.c:184
Datum macaddr_in(PG_FUNCTION_ARGS)
Definition: mac.c:30
unsigned char d
Definition: inet.h:99
static int32 macaddr_cmp_internal(macaddr *a1, macaddr *a2)
Definition: mac.c:156
Datum macaddr_trunc(PG_FUNCTION_ARGS)
Definition: mac.c:306
char * c
static char * buf
Definition: pg_test_fsync.c:65
Datum macaddr_not(PG_FUNCTION_ARGS)
Definition: mac.c:252
Datum macaddr_send(PG_FUNCTION_ARGS)
Definition: mac.c:135
#define ereport(elevel, rest)
Definition: elog.h:122
Datum macaddr_or(PG_FUNCTION_ARGS)
Definition: mac.c:285
unsigned char b
Definition: inet.h:97
Datum macaddr_eq(PG_FUNCTION_ARGS)
Definition: mac.c:202
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:303
uintptr_t Datum
Definition: postgres.h:374
unsigned char e
Definition: inet.h:100
Datum macaddr_ne(PG_FUNCTION_ARGS)
Definition: mac.c:229
static FormData_pg_attribute a1
Definition: heap.c:142
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:432
Datum macaddr_out(PG_FUNCTION_ARGS)
Definition: mac.c:95
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
Datum macaddr_recv(PG_FUNCTION_ARGS)
Definition: mac.c:114
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:306
Definition: inet.h:94
Datum macaddr_and(PG_FUNCTION_ARGS)
Definition: mac.c:268
Datum macaddr_cmp(PG_FUNCTION_ARGS)
Definition: mac.c:171
e
Definition: preproc-init.c:82
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:233
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
Datum macaddr_gt(PG_FUNCTION_ARGS)
Definition: mac.c:220
static FormData_pg_attribute a2
Definition: heap.c:148