aboutsummaryrefslogtreecommitdiff
path: root/software/main/SimplePgSQL.h
blob: 9637ee5e0d810e0aea20fd98599235ed52bd39a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
 * SimplePgSQL.h - Lightweight PostgreSQL connector for Arduino
 * Copyright (C) Bohdan R. Rau 2016 <ethanak@polip.com>
 *
 * SimplePgSQL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * SimplePgSQL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with SimplePgSQL.  If not, write to:
 * 	The Free Software Foundation, Inc.,
 * 	51 Franklin Street, Fifth Floor
 * 	Boston, MA  02110-1301, USA.
 */

#include <stdio.h>
#include <string.h>
#include "esp_system.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"

#ifndef _SIMPLEPGSQL
#define _SIMPLEPGSQL 1

typedef enum {
	CONNECTION_OK, CONNECTION_BAD, CONNECTION_NEEDED, /* setDbLogin() needed */
	/* Internal states here */
	CONNECTION_AWAITING_RESPONSE, /* Waiting for a response from the postmaster.        */
	CONNECTION_AUTH_OK /* Received authentication; waiting for backend startup. */
} ConnStatusType;

#define PG_BUFFER_SIZE 4096

// maximum number of fields in backend response
// must not exceed number of bits in _formats and _null
#define PG_MAX_FIELDS 32

// ignore notices and notifications
#define PG_FLAG_IGNORE_NOTICES 1
// do not store column names
#define PG_FLAG_IGNORE_COLUMNS 2

// ready for next query
#define PG_RSTAT_READY        1   // command sent
#define PG_RSTAT_COMMAND_SENT 2   // column names in buffer
#define PG_RSTAT_HAVE_COLUMNS 4   // row values in buffer
#define PG_RSTAT_HAVE_ROW     8   // summary (number of tuples/affected rows) received
#define PG_RSTAT_HAVE_SUMMARY 16  // error message in buffer
#define PG_RSTAT_HAVE_ERROR   32  // notice/notification in buffer
#define PG_RSTAT_HAVE_NOTICE  64

#define PG_RSTAT_HAVE_MASK (PG_RSTAT_HAVE_COLUMNS | \
    PG_RSTAT_HAVE_ROW | \
    PG_RSTAT_HAVE_SUMMARY | \
    PG_RSTAT_HAVE_ERROR | \
    PG_RSTAT_HAVE_NOTICE)

#define PG_RSTAT_HAVE_MESSAGE (PG_RSTAT_HAVE_ERROR | PG_RSTAT_HAVE_NOTICE)

class PGconnection {
public:

	PGconnection(const int flags, const unsigned char *Buffer, const int bufSize);
	/*
	 * returns connection status.
	 * passwd may be null in case of 'trust' authorization.
	 * only 'trust', 'password' and 'md5' (if compiled in)
	 * authorization modes are implemented.
	 * ssl mode is not implemented.
	 * database name defaults to user name         *
	 */
	int PGsetDbLogin(const char *ServerIP, int ServerPort, const char *dbName, const char *dbUser, const char *dbPasswd, const char *charset);
	/*
	 * performs authorization tasks if needed
	 * returns current connection status
	 * must be called periodically until OK, BAD or NEEDED
	 */
	int PGstatus(void);
	/*
	 * sends termination command if possible
	 * closes client connection and frees internal buffer
	 */
	void PGclose(void);
	/*
	 * sends query to backend
	 * returns negative value on error
	 * or zero on success
	 */
	int PGexecute(const char *query);

	/* should be called periodically in idle state
	 * if notifications are enabled
	 * returns:
	 * - negative value on error
	 * - zero if no interesting data arrived
	 * - current data status if some data arrived
	 */
	int PGgetData(void);
	/*
	 * returns pointer to n-th column name in internal buffer
	 * if available or null if column number out of range
	 * will be invalidated on next getData call
	 */
	char *PGgetColumn(int n);
	/*
	 * returns pointer to n-th column value in internal buffer
	 * if available or null if column number out of range
	 * or value is NULL
	 * will be invalidated on next getData call
	 */
	char *PGgetValue(int);
	/*
	 * returns pointer to message (error or notice)
	 * if available or NULL
	 * will be invalidated on next getData call
	 */
	char *PGgetMessage(void);
	int PGdataStatus(void) {
		return result_status;
	}
	;
	int PGnfields(void) {
		return _nfields;
	}
	;
	int PGntuples(void) {
		return _ntuples;
	}
	;
	/*
	 * returns length of escaped string
	 * single quotes and E prefix (if needed)
	 * will be added.
	 */
	int PGescapeString(const char *inbuf, char *outbuf);
	/*
	 * returns length of escaped string
	 * double quotes will be added.
	 */
	int PGescapeName(const char *inbuf, char *outbuf);
	/*
	 * sends formatted query to backend
	 * returns negative value on error
	 * or zero on success
	 * Formatting sequences:
	 * %s - string literal (will be escaped with escapeString)
	 * %n - name (will be escaped with escapeName)
	 * %d - int (single quotes will be added)
	 * %l - long int (single quotes will be added)
	 * %% - % character
	 */
	int PGexecuteFormat(const char *format, ...);

private:
	int pqPacketSend(char pack_type, const char *buf, int buf_len);
	int pqGetc(char *);
	int pqGetInt4(int32_t *result);
	int pqGetInt2(int16_t *result);
	int pqGetnchar(char *s, int len);
	int pqSkipnchar(int len);
	int pqGets(char *s, int maxlen);
	int pqGetRowDescriptions(void);
	int pqGetRow(void);
	void setMsg(const char *, int);
	void setMsg_P(const char *, int);
	int pqGetNotice(int);
	int pqGetNotify(int32_t);
	char *_user;
	char *_passwd;
//	char *Buffer;
	char *_buffer;
//	int bufSize;
	int _bufSize;
	int bufPos;
	int writeMsgPart(const char *s, int len, int fine);
	int32_t writeFormattedQuery(int32_t length, const char *format, va_list va);
	int dataAvailable(void);
	int build_startup_packet(char *packet, const char *db, const char *charset);
	uint8_t conn_status;
	uint8_t attempts;
	/*
	 int32_t be_pid;
	 int32_t be_key;
	 */
	int16_t _nfields;
	int16_t _ntuples;
	uint32_t _formats;
	uint32_t _null;
	uint8_t _binary;
	uint8_t _flags;
	uint32_t _available;
	int result_status;
	// network stuff
	struct sockaddr_in DestAddr;
	int SockH = -1;
	int ipProtocol = 0;
	int AddrFamily = 0;
	int NetConnected=0;

};

#endif