1 /*-------
2 * Module: columninfo.c
3 *
4 * Description: This module contains routines related to
5 * reading and storing the field information from a query.
6 *
7 * Classes: ColumnInfoClass (Functions prefix: "CI_")
8 *
9 * API functions: none
10 *
11 * Comments: See "readme.txt" for copyright and license information.
12 *-------
13 */
14
15 #include "pgtypes.h"
16 #include "columninfo.h"
17
18 #include "connection.h"
19 #include <stdlib.h>
20 #include <string.h>
21 #include "pgapifunc.h"
22
23 #include <libpq-fe.h>
24
25 ColumnInfoClass *
CI_Constructor(void)26 CI_Constructor(void)
27 {
28 ColumnInfoClass *rv;
29
30 rv = (ColumnInfoClass *) malloc(sizeof(ColumnInfoClass));
31
32 if (rv)
33 {
34 rv->refcount = 0;
35 rv->num_fields = 0;
36 rv->coli_array = NULL;
37 }
38
39 return rv;
40 }
41
42
43 void
CI_Destructor(ColumnInfoClass * self)44 CI_Destructor(ColumnInfoClass *self)
45 {
46 CI_free_memory(self);
47
48 free(self);
49 }
50
51 /*
52 * Read in field descriptions from a libpq result set.
53 * If self is not null, then also store the information.
54 * If self is null, then just read, don't store.
55 */
56 BOOL
CI_read_fields_from_pgres(ColumnInfoClass * self,PGresult * pgres)57 CI_read_fields_from_pgres(ColumnInfoClass *self, PGresult *pgres)
58 {
59 Int2 lf;
60 int new_num_fields;
61 OID new_adtid, new_relid = 0, new_attid = 0;
62 Int2 new_adtsize;
63 Int4 new_atttypmod = -1;
64 char *new_field_name;
65
66 /* at first read in the number of fields that are in the query */
67 new_num_fields = PQnfields(pgres);
68
69 QLOG(0, "\tnFields: %d\n", new_num_fields);
70
71 if (self)
72 {
73 /* according to that allocate memory */
74 CI_set_num_fields(self, new_num_fields);
75 if (new_num_fields > 0 && NULL == self->coli_array)
76 return FALSE;
77 }
78
79 /* now read in the descriptions */
80 for (lf = 0; lf < new_num_fields; lf++)
81 {
82 new_field_name = PQfname(pgres, lf);
83 new_relid = PQftable(pgres, lf);
84 new_attid = PQftablecol(pgres, lf);
85 new_adtid = PQftype(pgres, lf);
86 new_adtsize = PQfsize(pgres, lf);
87
88 MYLOG(0, "READING ATTTYPMOD\n");
89 new_atttypmod = PQfmod(pgres, lf);
90
91 /* Subtract the header length */
92 switch (new_adtid)
93 {
94 case PG_TYPE_DATETIME:
95 case PG_TYPE_TIMESTAMP_NO_TMZONE:
96 case PG_TYPE_TIME:
97 case PG_TYPE_TIME_WITH_TMZONE:
98 break;
99 default:
100 new_atttypmod -= 4;
101 }
102 if (new_atttypmod < 0)
103 new_atttypmod = -1;
104
105 QLOG(0, "\tfieldname='%s', adtid=%d, adtsize=%d, atttypmod=%d (rel,att)=(%d,%d)\n", new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
106
107 if (self)
108 CI_set_field_info(self, lf, new_field_name, new_adtid, new_adtsize, new_atttypmod, new_relid, new_attid);
109 }
110
111 return TRUE;
112 }
113
114
115 void
CI_free_memory(ColumnInfoClass * self)116 CI_free_memory(ColumnInfoClass *self)
117 {
118 register Int2 lf;
119 int num_fields = self->num_fields;
120
121 /* Safe to call even if null */
122 self->num_fields = 0;
123 if (self->coli_array)
124 {
125 for (lf = 0; lf < num_fields; lf++)
126 {
127 if (self->coli_array[lf].name)
128 {
129 free(self->coli_array[lf].name);
130 self->coli_array[lf].name = NULL;
131 }
132 }
133 free(self->coli_array);
134 self->coli_array = NULL;
135 }
136 }
137
138
139 void
CI_set_num_fields(ColumnInfoClass * self,int new_num_fields)140 CI_set_num_fields(ColumnInfoClass *self, int new_num_fields)
141 {
142 CI_free_memory(self); /* always safe to call */
143
144 self->num_fields = new_num_fields;
145
146 self->coli_array = (struct srvr_info *) calloc(sizeof(struct srvr_info), self->num_fields);
147 }
148
149
150 void
CI_set_field_info(ColumnInfoClass * self,int field_num,const char * new_name,OID new_adtid,Int2 new_adtsize,Int4 new_atttypmod,OID new_relid,OID new_attid)151 CI_set_field_info(ColumnInfoClass *self, int field_num, const char *new_name,
152 OID new_adtid, Int2 new_adtsize, Int4 new_atttypmod,
153 OID new_relid, OID new_attid)
154 {
155 /* check bounds */
156 if ((field_num < 0) || (field_num >= self->num_fields))
157 return;
158
159 /* store the info */
160 self->coli_array[field_num].name = strdup(new_name);
161 self->coli_array[field_num].adtid= new_adtid;
162 self->coli_array[field_num].adtsize = new_adtsize;
163 self->coli_array[field_num].atttypmod = new_atttypmod;
164
165 self->coli_array[field_num].display_size = PG_ADT_UNSET;
166 self->coli_array[field_num].relid = new_relid;
167 self->coli_array[field_num].attid = new_attid;
168 }
169