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