FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
sqlCopy.c
Go to the documentation of this file.
1 /**************************************************************
2 Copyright (C) 2011 Hewlett-Packard Development Company, L.P.
3 
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License version 2.1 as published by the Free Software Foundation.
7 
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
12 
13 You should have received a copy of the GNU Lesser General Public License
14 along with this library; if not, write to the Free Software Foundation, Inc.0
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 **************************************************************/
17 
46 #include "sqlCopy.h"
47 
62 psqlCopy_t fo_sqlCopyCreate(PGconn* pGconn, char* TableName, int BufSize, int NumColumns, ...)
63 {
64  psqlCopy_t pCopy;
65  va_list ColumnNameArg;
66  int ColIdx;
67  int ColStrLength;
68  char* ColStr;
69 
70  va_start(ColumnNameArg, NumColumns);
71 
72  /* Allocate the structure */
73  pCopy = malloc(sizeof(sqlCopy_t));
74  if (!pCopy)
75  {
76  va_end(ColumnNameArg);
77  ERROR_RETURN("sqlCopy malloc")
78  }
79 
80  /* Allocate storage for the data buffer */
81  if (BufSize < 1) BufSize = 1;
82  pCopy->DataBuf = calloc(BufSize, sizeof(char));
83 
84  /* Save TableName */
85  pCopy->TableName =g_strdup(TableName);
86 
87  /* check for malloc failures */
88  if ((!pCopy->DataBuf) || (!pCopy->TableName))
89  {
90  fo_sqlCopyDestroy(pCopy, 0);
91  va_end(ColumnNameArg);
92  ERROR_RETURN("sqlCopyCreate")
93  }
94 
95  /* Save the DB connection */
96  pCopy->pGconn = pGconn;
97 
98  /* Save the data buffer size */
99  pCopy->BufSize = BufSize;
100 
101  /* Data buffer is empty */
102  pCopy->DataIdx = 0;
103 
104  /* Build the column name string pCopy->ColumnNames */
105  ColStrLength = 0;
106  pCopy->ColumnNames[0] = 0;
107  for (ColIdx = 0; ColIdx < NumColumns; ColIdx++)
108  {
109  ColStr = va_arg(ColumnNameArg, char *);
110  ColStrLength += strlen(ColStr) + 1; /* extra 1 for the comma */
111  if (ColStrLength < sizeof(pCopy->ColumnNames))
112  {
113  if (ColIdx != 0) strncat(pCopy->ColumnNames, ",", 1);
114  strncat(pCopy->ColumnNames, ColStr, ColStrLength);
115  }
116  else
117  {
118  fo_sqlCopyDestroy(pCopy, 0);
119  va_end(ColumnNameArg);
120  ERROR_RETURN("pCopy->ColumnNames size too small")
121  }
122  }
123  va_end(ColumnNameArg);
124  return (pCopy);
125 } /* End fo_sqlCopyCreate() */
126 
127 
128 #ifdef DEBUG
129 int tmp_printhex(char * str)
130 {
131  while(*str) printf("%02x", *str++);
132  return(0);
133 }
134 #endif
135 
136 #define growby 128
137 
138 
157 int fo_sqlCopyAdd(psqlCopy_t pCopy, char* DataRow)
158 {
159  int NewRowLen;
160  int rncount = 0;
161  char* dptr = DataRow;
162  char* NewRow = 0, * nptr;
163 
164  /* As of Postgresql 8.4, COPY will not accept embedded literal carriage returns
165  * or line feeds. Use "\r" and "\n" instead.
166  * Count how many we need to get rid of (and make space for).
167  */
168  while (*dptr)
169  {
170  if (((*dptr == '\n') || (*dptr == '\r')) && (*(dptr + 1))) rncount++;
171  dptr++;
172  }
173 
174  /* Substitute any literal '\n' or '\r' for string "\n", "\r"
175  * (except for trailing \n which is required)
176  */
177  if (rncount)
178  {
179  NewRowLen = strlen(DataRow) + rncount;
180  NewRow = malloc(NewRowLen + 1); // plus 1 for potential required \n at end
181  if (!NewRow)
182  ERROR_RETURN("fo_sqlCopyAdd: out of memory");
183  nptr = NewRow;
184  dptr = DataRow;
185  while (*dptr && *(dptr + 1))
186  {
187  if (*dptr == '\n')
188  {
189  *nptr++ = '\\';
190  *nptr = 'n';
191  }
192  else if (*dptr == '\r')
193  {
194  *nptr++ = '\\';
195  *nptr = 'r';
196  }
197  else
198  *nptr = *dptr;
199  ++dptr;
200  ++nptr;
201  }
202  *nptr = 0; // null terminator
203  DataRow = NewRow;
204  }
205 
206  /* Does new record fit in DataBuf? */
207  NewRowLen = strlen(DataRow);
208  if ((pCopy->BufSize - pCopy->DataIdx) < (NewRowLen + 1))
209  {
210  /* if DataIdx is zero, then DataBuf isn't big enough to hold
211  * this record. In this case make DataBuf larger.
212  */
213  if (pCopy->DataIdx == 0)
214  {
215  pCopy->DataBuf = realloc(pCopy->DataBuf, NewRowLen + growby);
216  if (!pCopy->DataBuf)
217  ERROR_RETURN("fo_sqlCopyAdd: Realloc for DataBuf failed");
218  pCopy->BufSize = NewRowLen + growby;
219  }
220  else
221  {
222  /* Execute a copy to make room in DataBuf */
223  fo_sqlCopyExecute(pCopy);
224  }
225  }
226 
227  /* copy in DataRow */
228  strcpy(pCopy->DataBuf + pCopy->DataIdx, DataRow);
229  pCopy->DataIdx += NewRowLen;
230 
231  /* If the DataRow was missing a terminating newline, add one */
232  if (DataRow[NewRowLen - 1] != '\n')
233  {
234  pCopy->DataBuf[pCopy->DataIdx++] = '\n';
235  pCopy->DataBuf[pCopy->DataIdx] = 0; // new null terminator
236  }
237 
238  if (NewRow) free(NewRow);
239  return (1);
240 }
241 
253 {
254  char copystmt[2048];
255  PGresult* result;
256 
257  /* check pCopy */
258  if (!pCopy)
259  ERROR_RETURN("Null pCopy");
260  if (pCopy->DataIdx == 0) return (1); /* nothing to copy */
261 
262  /* Start the Copy command */
263  sprintf(copystmt, "COPY %s(%s) from stdin",
264  pCopy->TableName,
265  pCopy->ColumnNames);
266  result = PQexec(pCopy->pGconn, copystmt);
267  if (PGRES_COPY_IN == PQresultStatus(result))
268  {
269  PQclear(result);
270  if (PQputCopyData(pCopy->pGconn, pCopy->DataBuf, pCopy->DataIdx) != 1)
271  ERROR_RETURN(PQresultErrorMessage(result))
272  }
273  else if (fo_checkPQresult(pCopy->pGconn, result, copystmt, __FILE__, __LINE__)) return 0;
274 
275 
276  /* End copy */
277  if (PQputCopyEnd(pCopy->pGconn, NULL) == 1)
278  {
279  result = PQgetResult(pCopy->pGconn);
280  if (fo_checkPQcommand(pCopy->pGconn, result, "copy end", __FILE__, __LINE__)) return 0;
281  }
282  PQclear(result);
283 
284  /* reset DataBuf */
285  pCopy->DataIdx = 0;
286 
287  return (1);
288 }
289 
290 
304 void fo_sqlCopyDestroy(psqlCopy_t pCopy, int ExecuteFlag)
305 {
306  if (!pCopy) return;
307  if (ExecuteFlag) fo_sqlCopyExecute(pCopy);
308  if (pCopy->TableName) free(pCopy->TableName);
309  if (pCopy->DataBuf) free(pCopy->DataBuf);
310  free(pCopy);
311 }
312 
313 
324 void fo_sqlCopyPrint(psqlCopy_t pCopy, int PrintBytes)
325 {
326  int idx;
327 
328  printf("========== fo_sqlCopyPrint Start ================\n");
329  printf("pCopy: %lx, TableName: %s, BufSize: %d, DataIdx: %d\n",
330  (long) pCopy, pCopy->TableName, pCopy->BufSize, pCopy->DataIdx);
331  printf(" ColumnNames: %s\n", pCopy->ColumnNames);
332 
333  if (PrintBytes == 0) PrintBytes = pCopy->DataIdx;
334  for (idx = 0; idx < PrintBytes; idx++) putchar(pCopy->DataBuf[idx]);
335 
336  printf("========== fo_sqlCopyPrint End ================");
337 }
int fo_checkPQresult(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres SELECT.
Definition: libfossdb.c:181
char ColumnNames[1024]
Definition: sqlCopy.h:43
char * TableName
Definition: sqlCopy.h:41
int fo_checkPQcommand(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres commands (not select) If an error occured, write the error to s...
Definition: libfossdb.c:215
PGconn * pGconn
Definition: sqlCopy.h:39
psqlCopy_t fo_sqlCopyCreate(PGconn *pGconn, char *TableName, int BufSize, int NumColumns,...)
Constructor for sqlCopy_struct.
Definition: sqlCopy.c:62
int fo_sqlCopyExecute(psqlCopy_t pCopy)
Execute the copy (ie insert the buffered records into the database).
Definition: sqlCopy.c:252
#define growby
Grow DataBuf by this number of bytes.
Definition: sqlCopy.c:136
void fo_sqlCopyDestroy(psqlCopy_t pCopy, int ExecuteFlag)
Destructor for sqlCopy_struct.
Definition: sqlCopy.c:304
void fo_sqlCopyPrint(psqlCopy_t pCopy, int PrintBytes)
Print the sqlCopy_struct.
Definition: sqlCopy.c:324
int fo_sqlCopyAdd(psqlCopy_t pCopy, char *DataRow)
Add a data row to an sqlCopy Use &#39;&#39; to pass in a null.
Definition: sqlCopy.c:157