NCBI C++ ToolKit
dbpivot.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 2011 James K. Lowden
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 #include <config.h>
21 
22 #include <stdarg.h>
23 
24 #include <freetds/time.h>
25 
26 #include <assert.h>
27 #include <stdio.h>
28 
29 #if HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif /* HAVE_STDLIB_H */
32 
33 #if HAVE_STRING_H
34 #include <string.h>
35 #endif /* HAVE_STRING_H */
36 
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif /* HAVE_UNISTD_H */
40 
41 #if HAVE_ERRNO_H
42 # include <errno.h>
43 #endif /* HAVE_ERRNO_H */
44 
45 
46 #include <freetds/tds.h>
47 #include <freetds/thread.h>
48 #include <freetds/convert.h>
49 #include <freetds/string.h>
50 #include <replacements.h>
51 #include <sybfront.h>
52 #include <sybdb.h>
53 #include <syberror.h>
54 #include <dblib.h>
55 
56 #define TDS_FIND(k,b,c) tds_find(k, b, sizeof(b)/sizeof(b[0]), sizeof(b[0]), c)
57 
58 typedef bool (*compare_func)(const void *, const void *);
59 
60 static void *
61 tds_find(const void *key, const void *base, size_t nelem, size_t width,
62  compare_func compar)
63 {
64  size_t i;
65  for (i=0; i < nelem; i++) {
66  char *p = (char*)base + width * i;
67  if (true == compar(key, p)) {
68  return p;
69  }
70  }
71  return NULL;
72 }
73 
74 
75 struct col_t
76 {
77  size_t len;
80  char *s;
81  union {
87  } data;
88 };
89 
90 static TDS_SERVER_TYPE infer_col_type(int sybtype);
91 
92 static struct col_t *
93 col_init(struct col_t *pcol, int sybtype, size_t collen)
94 {
95  assert(pcol);
96 
97  pcol->type = infer_col_type(sybtype);
98  if (pcol->type == TDS_INVALID_TYPE)
99  return NULL;
100  pcol->len = collen;
101  pcol->s = NULL;
102 
103  switch(sybtype) {
104  case 0:
105  pcol->len = 0;
106  return NULL;
107  case SYBDATETIME:
108  case SYBDATETIME4:
109  case SYBDATETIMN:
110  collen = 30;
111  case SYBCHAR:
112  case SYBVARCHAR:
113  case SYBTEXT:
114  case SYBNTEXT:
115  pcol->len = collen;
116  if ((pcol->s = tds_new(char, 1+collen)) == NULL) {
117  return NULL;
118  }
119  break;
120  }
121  return pcol;
122 }
123 
124 static void
125 col_free(struct col_t *p)
126 {
127  free(p->s);
128  memset(p, 0, sizeof(*p));
129 }
130 
131 static bool
132 col_equal(const struct col_t *pc1, const struct col_t *pc2)
133 {
134  assert( pc1 && pc2 );
135  assert( pc1->type == pc2->type );
136 
137  switch(pc1->type) {
138 
139  case SYBCHAR:
140  case SYBVARCHAR:
141  if( pc1->len != pc2->len)
142  return false;
143  return strncmp(pc1->s, pc2->s, pc1->len) == 0? true : false;
144  case SYBINT1:
145  return pc1->data.ti == pc2->data.ti? true : false;
146  case SYBINT2:
147  return pc1->data.si == pc2->data.si? true : false;
148  case SYBINT4:
149  return pc1->data.i == pc2->data.i? true : false;
150  case SYBFLT8:
151  return pc1->data.f == pc2->data.f? true : false;
152  case SYBREAL:
153  return pc1->data.r == pc2->data.r? true : false;
154 
155  case SYBINTN:
156  case SYBDATETIME:
157  case SYBBIT:
158  case SYBTEXT:
159  case SYBNTEXT:
160  case SYBIMAGE:
161  case SYBMONEY4:
162  case SYBMONEY:
163  case SYBDATETIME4:
164  case SYBBINARY:
165  case SYBVOID:
166  case SYBVARBINARY:
167  case SYBBITN:
168  case SYBNUMERIC:
169  case SYBDECIMAL:
170  case SYBFLTN:
171  case SYBMONEYN:
172  case SYBDATETIMN:
173  assert( false && pc1->type );
174  break;
175 
176  default:
177  return false;
178  }
179  return false;
180 }
181 
182 static void *
183 col_buffer(struct col_t *pcol)
184 {
185  switch(pcol->type) {
186 
187  case SYBCHAR:
188  case SYBVARCHAR:
189  return pcol->s;
190  case SYBINT1:
191  return &pcol->data.ti;
192  case SYBINT2:
193  return &pcol->data.si;
194  case SYBINT4:
195  return &pcol->data.i;
196  case SYBFLT8:
197  return &pcol->data.f;
198  case SYBREAL:
199  return &pcol->data.r;
200 
201  case SYBINTN:
202  case SYBDATETIME:
203  case SYBBIT:
204  case SYBTEXT:
205  case SYBNTEXT:
206  case SYBIMAGE:
207  case SYBMONEY4:
208  case SYBMONEY:
209  case SYBDATETIME4:
210  case SYBBINARY:
211  case SYBVOID:
212  case SYBVARBINARY:
213  case SYBBITN:
214  case SYBNUMERIC:
215  case SYBDECIMAL:
216  case SYBFLTN:
217  case SYBMONEYN:
218  case SYBDATETIMN:
219  assert( false && pcol->type );
220  break;
221 
222  default:
223  return NULL;
224  }
225  return NULL;
226 
227 }
228 
229 #if 0
230 static int
231 col_print(FILE* out, const struct col_t *pcol)
232 {
233  char *fmt;
234 
235  switch(pcol->type) {
236 
237  case SYBCHAR:
238  case SYBVARCHAR:
239  return (int) fwrite(pcol->s, pcol->len, 1, out);
240  case SYBINT1:
241  return fprintf(out, "%d", (int)pcol->ti);
242  case SYBINT2:
243  return fprintf(out, "%d", (int)pcol->si);
244  case SYBINT4:
245  return fprintf(out, "%d", (int)pcol->i);
246  case SYBFLT8:
247  return fprintf(out, "%f", pcol->f);
248  case SYBREAL:
249  return fprintf(out, "%f", (double)pcol->r);
250 
251  case SYBINTN:
252  case SYBDATETIME:
253  case SYBBIT:
254  case SYBTEXT:
255  case SYBNTEXT:
256  case SYBIMAGE:
257  case SYBMONEY4:
258  case SYBMONEY:
259  case SYBDATETIME4:
260  case SYBBINARY:
261  case SYBVOID:
262  case SYBVARBINARY:
263  case SYBBITN:
264  case SYBNUMERIC:
265  case SYBDECIMAL:
266  case SYBFLTN:
267  case SYBMONEYN:
268  case SYBDATETIMN:
269  assert( false && pcol->type );
270  break;
271  }
272  return false;
273 }
274 #endif
275 static struct col_t *
276 col_cpy(struct col_t *pdest, const struct col_t *psrc)
277 {
278  assert( pdest && psrc );
279  assert( psrc->len > 0 || psrc->null_indicator == -1);
280 
281  memcpy(pdest, psrc, sizeof(*pdest));
282 
283  if (psrc->s) {
284  assert(psrc->len >= 0);
285  if ((pdest->s = tds_new(char, psrc->len)) == NULL)
286  return NULL;
287  memcpy(pdest->s, psrc->s, psrc->len);
288  }
289 
290  assert( pdest->len > 0 || pdest->null_indicator == -1);
291  return pdest;
292 }
293 
294 static bool
295 col_null( const struct col_t *pcol )
296 {
297  assert(pcol);
298  return pcol->null_indicator == -1? true : false;
299 }
300 
301 static char *
302 string_value(const struct col_t *pcol)
303 {
304  char *output = NULL;
305  int len = -1;
306 
307  switch(pcol->type) {
308  case SYBCHAR:
309  case SYBVARCHAR:
310  if ((output = tds_new0(char, 1 + pcol->len)) == NULL)
311  return NULL;
312  strncpy(output, pcol->s, pcol->len);
313  return output;
314  break;
315  case SYBINT1:
316  len = asprintf(&output, "%d", (int)pcol->data.ti);
317  break;
318  case SYBINT2:
319  len = asprintf(&output, "%d", (int)pcol->data.si);
320  break;
321  case SYBINT4:
322  len = asprintf(&output, "%d", (int)pcol->data.i);
323  break;
324  case SYBFLT8:
325  len = asprintf(&output, "%f", pcol->data.f);
326  break;
327  case SYBREAL:
328  len = asprintf(&output, "%f", (double)pcol->data.r);
329  break;
330 
331  default:
332  case SYBINTN:
333  case SYBDATETIME:
334  case SYBBIT:
335  case SYBTEXT:
336  case SYBNTEXT:
337  case SYBIMAGE:
338  case SYBMONEY4:
339  case SYBMONEY:
340  case SYBDATETIME4:
341  case SYBBINARY:
342  case SYBVOID:
343  case SYBVARBINARY:
344  case SYBBITN:
345  case SYBNUMERIC:
346  case SYBDECIMAL:
347  case SYBFLTN:
348  case SYBMONEYN:
349  case SYBDATETIMN:
350  assert( false && pcol->type );
351  return NULL;
352  break;
353  }
354 
355  return len >= 0? output : NULL;
356 }
357 
358 static char *
359 join(int argc, char *argv[], const char sep[])
360 {
361  size_t len = 0;
362  char **p, *output;
363 
364  for (p=argv; p < argv + argc; p++) {
365  len += strlen(*p);
366  }
367 
368  len += 1 + argc * strlen(sep); /* allows one too many */
369 
370  output = tds_new0(char, len);
371 
372  for (p=argv; p < argv + argc; p++) {
373  if (p != argv)
374  strcat(output, sep);
375  strcat(output, *p);
376  }
377  return output;
378 }
379 
380 static TDS_SERVER_TYPE
381 infer_col_type(int sybtype)
382 {
383  switch(sybtype) {
384  case SYBCHAR:
385  case SYBVARCHAR:
386  case SYBTEXT:
387  case SYBNTEXT:
388  return SYBCHAR;
389  case SYBDATETIME:
390  case SYBDATETIME4:
391  case SYBDATETIMN:
392  return SYBCHAR;
393  case SYBINT1:
394  case SYBBIT:
395  case SYBBITN:
396  return SYBINT1;
397  case SYBINT2:
398  return SYBINT2;
399  case SYBINT4:
400  case SYBINTN:
401  return SYBINT4;
402  case SYBFLT8:
403  case SYBMONEY4:
404  case SYBMONEY:
405  case SYBFLTN:
406  case SYBMONEYN:
407  case SYBNUMERIC:
408  case SYBDECIMAL:
409  return SYBFLT8;
410  case SYBREAL:
411  return SYBREAL;
412 
413  case SYBIMAGE:
414  case SYBBINARY:
415  case SYBVOID:
416  case SYBVARBINARY:
417  assert( false && sybtype );
418  break;
419  }
420  return TDS_INVALID_TYPE;
421 }
422 
423 static int
424 bind_type(int sybtype)
425 {
426  switch(sybtype) {
427  case SYBCHAR:
428  case SYBVARCHAR:
429  case SYBTEXT:
430  case SYBNTEXT:
431  case SYBDATETIME:
432  case SYBDATETIME4:
433  case SYBDATETIMN:
434  return NTBSTRINGBIND;
435  case SYBINT1:
436  case SYBBIT:
437  case SYBBITN:
438  return TINYBIND;
439  case SYBINT2:
440  return SMALLBIND;
441  case SYBINT4:
442  case SYBINTN:
443  return INTBIND;
444  case SYBFLT8:
445  case SYBMONEY4:
446  case SYBMONEY:
447  case SYBFLTN:
448  case SYBMONEYN:
449  case SYBNUMERIC:
450  case SYBDECIMAL:
451  return FLT8BIND;
452  case SYBREAL:
453  return REALBIND;
454 
455  case SYBIMAGE:
456  case SYBBINARY:
457  case SYBVOID:
458  case SYBVARBINARY:
459  assert( false && sybtype );
460  break;
461  }
462  return 0;
463 }
464 
465 typedef struct KEY_T
466 {
467  int nkeys;
468  struct col_t *keys;
470 
471 static bool
472 key_equal(const KEY_T *a, const KEY_T *b)
473 {
474  int i;
475 
476  assert(a && b);
477  assert(a->keys && b->keys);
478  assert(a->nkeys == b->nkeys);
479 
480  for (i=0; i < a->nkeys; i++) {
481  if (! col_equal(a->keys+i, b->keys+i))
482  return false;
483  }
484  return true;
485 }
486 
487 
488 static void
490 {
491  col_free(p->keys);
492  free(p->keys);
493  memset(p, 0, sizeof(*p));
494 }
495 
496 static KEY_T *
497 key_cpy(KEY_T *pdest, const KEY_T *psrc)
498 {
499  int i;
500 
501  assert( pdest && psrc );
502 
503  if ((pdest->keys = tds_new0(struct col_t, psrc->nkeys)) == NULL)
504  return NULL;
505 
506  pdest->nkeys = psrc->nkeys;
507 
508  for( i=0; i < psrc->nkeys; i++) {
509  if (NULL == col_cpy(pdest->keys+i, psrc->keys+i))
510  return NULL;
511  }
512 
513  return pdest;
514 }
515 
516 
517 static char *
519 {
520  const struct col_t *pc;
521  char **names, **s, *output;
522 
523  assert(k);
524  assert(k->nkeys);
525  assert(k->keys);
526 
527  s = names = tds_new0(char *, k->nkeys);
528  if (!s) {
529  dbperror(dbproc, SYBEMEM, errno);
530  return NULL;
531  }
532  for(pc=k->keys; pc < k->keys + k->nkeys; pc++) {
533  *s++ = string_value(pc);
534  }
535 
536  output = join(k->nkeys, names, "/");
537 
538  for(s=names; s < names + k->nkeys; s++) {
539  free(*s);
540  }
541  free(names);
542 
543  return output;
544 }
545 
546 
547 typedef struct agg_t
548 {
550  struct col_t value;
552 
553 #if 0
554 static bool
555 agg_key_equal(const void *a, const void *b)
556 {
557  int i;
558  const AGG_T *p1 = a, *p2 = b;
559 
560  assert(p1 && p2);
561  assert(p1->row_key.keys && p2->row_key.keys);
562  assert(p1->row_key.nkeys == p2->row_key.nkeys);
563 
564  for( i=0; i < p1->row_key.nkeys; i++ ) {
565  if (! col_equal(p1->row_key.keys+i, p2->row_key.keys+i))
566  return false;
567  }
568 
569  return true;
570 }
571 #endif
572 
573 static bool
574 agg_next(const AGG_T *p1, const AGG_T *p2)
575 {
576  int i;
577 
578  assert(p1 && p2);
579 
580  if (p1->row_key.keys == NULL || p2->row_key.keys == NULL)
581  return false;
582 
583  assert(p1->row_key.keys && p2->row_key.keys);
584  assert(p1->row_key.nkeys == p2->row_key.nkeys);
585 
586  assert(p1->col_key.keys && p2->col_key.keys);
587  assert(p1->col_key.nkeys == p2->col_key.nkeys);
588 
589  for( i=0; i < p1->row_key.nkeys; i++ ) {
590  assert(p1->row_key.keys[i].type);
591  assert(p2->row_key.keys[i].type);
592  if (p1->row_key.keys[i].type != p2->row_key.keys[i].type)
593  return false;
594  }
595 
596  for( i=0; i < p1->row_key.nkeys; i++ ) {
597  if (! col_equal(p1->row_key.keys+i, p2->row_key.keys+i))
598  return false;
599  }
600 
601  for( i=0; i < p1->col_key.nkeys; i++ ) {
602  if (p1->col_key.keys[i].type != p2->col_key.keys[i].type)
603  return false;
604  }
605 
606  for( i=0; i < p1->col_key.nkeys; i++ ) {
607  if (! col_equal(p1->col_key.keys+i, p2->col_key.keys+i))
608  return false;
609  }
610 
611  return true;
612 }
613 
614 static void
616 {
617  key_free(&p->row_key);
618  key_free(&p->col_key);
619  col_free(&p->value);
620 }
621 
622 static bool
623 agg_equal(const AGG_T *p1, const AGG_T *p2)
624 {
625  int i;
626 
627  assert(p1 && p2);
628  assert(p1->row_key.keys && p1->col_key.keys);
629  assert(p2->row_key.keys && p2->col_key.keys);
630 
631  assert(p1->row_key.nkeys == p2->row_key.nkeys);
632  assert(p1->col_key.nkeys == p2->col_key.nkeys);
633 
634  /* todo: use key_equal */
635  for( i=0; i < p1->row_key.nkeys; i++ ) {
636  if (! col_equal(p1->row_key.keys+i, p2->row_key.keys+i))
637  return false;
638  }
639  for( i=0; i < p1->col_key.nkeys; i++ ) {
640  if (! col_equal(p1->col_key.keys+i, p2->col_key.keys+i))
641  return false;
642  }
643  return true;
644 }
645 
646 #undef TEST_MALLOC
647 #define TEST_MALLOC(dest,type) \
648  {if (!(dest = (type*)calloc(1, sizeof(type)))) goto Cleanup;}
649 
650 #undef TEST_CALLOC
651 #define TEST_CALLOC(dest,type,n) \
652  {if (!(dest = (type*)calloc((n), sizeof(type)))) goto Cleanup;}
653 
654 #define tds_alloc_column() ((TDSCOLUMN*) calloc(1, sizeof(TDSCOLUMN)))
655 
656 static TDSRESULTINFO *
658 {
659  TDSRESULTINFO *res_info;
660  TDSCOLUMN **ppcol;
661 
662  TEST_MALLOC(res_info, TDSRESULTINFO);
663  res_info->ref_count = 1;
664  TEST_CALLOC(res_info->columns, TDSCOLUMN *, num_cols);
665 
666  for (ppcol = res_info->columns; ppcol < res_info->columns + num_cols; ppcol++)
667  if ((*ppcol = tds_alloc_column()) == NULL)
668  goto Cleanup;
669  res_info->num_cols = num_cols;
670  res_info->row_size = 0;
671  return res_info;
672 
673  Cleanup:
674  tds_free_results(res_info);
675  return NULL;
676 }
677 
678 static TDSRET
679 set_result_column(TDSSOCKET * tds, TDSCOLUMN * curcol, const char name[], const struct col_t *pvalue)
680 {
681  assert(curcol && pvalue);
682  assert(name);
683 
684  curcol->column_usertype = pvalue->type;
685  curcol->column_nullable = true;
686  curcol->column_writeable = false;
687  curcol->column_identity = false;
688 
689  tds_set_column_type(tds->conn, curcol, pvalue->type); /* sets "cardinal" type */
690 
691  curcol->column_timestamp = (curcol->column_type == SYBBINARY && curcol->column_usertype == TDS_UT_TIMESTAMP);
692 
693 #if 0
694  curcol->funcs->get_info(tds, curcol);
695 #endif
696  curcol->on_server.column_size = curcol->column_size;
697 
698  if (!tds_dstr_copy(&curcol->column_name, name))
699  return TDS_FAIL;
700 
701  tdsdump_log(TDS_DBG_INFO1, "tds7_get_data_info: \n"
702  "\tcolname = %s\n"
703  "\ttype = %d (%s)\n"
704  "\tserver's type = %d (%s)\n"
705  "\tcolumn_varint_size = %d\n"
706  "\tcolumn_size = %d (%d on server)\n",
707  tds_dstr_cstr(&curcol->column_name),
708  curcol->column_type, tds_prtype(curcol->column_type),
710  curcol->column_varint_size,
711  curcol->column_size, curcol->on_server.column_size);
712 
713  return TDS_SUCCESS;
714 }
715 
716 struct metadata_t { KEY_T *pacross; char *name; struct col_t col; };
717 
718 
719 static bool
721  const struct metadata_t meta[])
722 {
724  int i;
725 
726  assert(tds);
727  assert(num_cols);
728  assert(meta);
729 
732 
733  if ((info = alloc_results(num_cols)) == NULL)
734  return false;
735 
737  if (tds->cur_cursor) {
740  tdsdump_log(TDS_DBG_INFO1, "set current_results to cursor->res_info\n");
741  } else {
742  tds->res_info = info;
743  tdsdump_log(TDS_DBG_INFO1, "set current_results (%u column%s) to tds->res_info\n", (unsigned) num_cols, (num_cols==1? "":"s"));
744  }
745 
746  tdsdump_log(TDS_DBG_INFO1, "setting up %u columns\n", (unsigned) num_cols);
747 
748  for (i = 0; i < num_cols; i++) {
749  set_result_column(tds, info->columns[i], meta[i].name, &meta[i].col);
750  info->columns[i]->bcp_terminator = (char*) meta[i].pacross; /* overload available pointer */
751  }
752 
753  if (num_cols > 0) {
754  static const char dashes[31] = "------------------------------";
755  tdsdump_log(TDS_DBG_INFO1, " %-20s %-15s %-15s %-7s\n", "name", "size/wsize", "type/wtype", "utype");
756  tdsdump_log(TDS_DBG_INFO1, " %-20s %15s %15s %7s\n", dashes+10, dashes+30-15, dashes+30-15, dashes+30-7);
757  }
758  for (i = 0; i < num_cols; i++) {
759  TDSCOLUMN *curcol = info->columns[i];
760 
761  tdsdump_log(TDS_DBG_INFO1, " %-20s %7d/%-7d %7d/%-7d %7d\n",
762  tds_dstr_cstr(&curcol->column_name),
763  curcol->column_size, curcol->on_server.column_size,
764  curcol->column_type, curcol->on_server.column_type,
765  curcol->column_usertype);
766  }
767 
768 #if 1
769  /* all done now allocate a row for tds_process_row to use */
770  if (TDS_FAILED(tds_alloc_row(info))) return false;
771 #endif
772  return true;
773 }
774 
775 typedef struct pivot_t
776 {
780 
783  size_t nout;
786 
787 static bool
789 {
790  assert(a && b);
791 
792  return a->dbproc == b->dbproc? true : false;
793 }
794 
795 static PIVOT_T *pivots = NULL;
796 static size_t npivots = 0;
797 
798 PIVOT_T *
800 {
801  PIVOT_T P;
802 
803  assert(dbproc);
804  P.dbproc = dbproc;
805 
806  return (PIVOT_T *) tds_find(&P, pivots, npivots, sizeof(*pivots), (compare_func) pivot_key_equal);
807 }
808 
809 STATUS
811 {
812  int i;
813  AGG_T candidate, *pout;
814 
815  assert(pp);
819 
820  for (pout = pp->output; pout < pp->output + pp->nout; pout++) {
821  if (pout->row_key.keys != NULL)
822  break;
823  }
824 
825  if (pout == pp->output + pp->nout) {
827  return NO_MORE_ROWS;
828  }
829 
830  memset(&candidate, 0, sizeof(candidate));
831  key_cpy(&candidate.row_key, &pout->row_key);
832 
833  /* "buffer_transfer_bound_data" */
834  for (i = 0; i < dbproc->tds_socket->res_info->num_cols; i++) {
835  struct col_t *pval = NULL;
837  assert(pcol);
838 
839  if (pcol->column_nullbind) {
840  if (pcol->column_cur_size < 0) {
841  *(DBINT *)(pcol->column_nullbind) = -1;
842  } else {
843  *(DBINT *)(pcol->column_nullbind) = 0;
844  }
845  }
846  if (!pcol->column_varaddr) {
848  "no pcol->column_varaddr in col %d\n", i);
849  continue;
850  }
851 
852  /* find column in output */
853  if (pcol->bcp_terminator == NULL) { /* not a cross-tab column */
854  pval = &candidate.row_key.keys[i];
855  } else {
856  AGG_T *pcan;
857  key_cpy(&candidate.col_key, (KEY_T *) pcol->bcp_terminator);
858  if ((pcan = (AGG_T *) tds_find
859  (&candidate, pout, pp->output + pp->nout - pout,
860  sizeof(*pp->output), (compare_func) agg_next))
861  != NULL) {
862  /* flag this output as used */
863  pout->row_key.keys = NULL;
864  pval = &pcan->value;
865  }
866  }
867 
868  if (!pval || col_null(pval)) { /* nothing in output for this x,y location */
870  continue;
871  }
872 
873  assert(pval);
874 
875 #if 0
877  "copying col %d, type %d/%d, len %d to %p\n",
878  i, pval->type, pcol->column_type, pval->len,
879  pcol->column_varaddr);
880  switch (pval->type) {
881  case 48:
882  tdsdump_log(TDS_DBG_FUNC, "value %d\n", (int)pval->ti);
883  break;
884  case 56:
885  tdsdump_log(TDS_DBG_FUNC, "value %d\n", (int)pval->si);
886  break;
887  }
888 #endif
889  pcol->column_size = pval->len;
890  pcol->column_data = (unsigned char *) col_buffer(pval);
891 
893  pval->type,
894  (BYTE *) col_buffer(pval),
895  pval->len,
896  (BYTE *) pcol->column_varaddr,
897  pcol->column_bindlen,
898  pcol->column_bindtype,
899  (DBINT*) pcol->column_nullbind
900  );
901  }
902 
903  return REG_ROW;
904 }
905 
906 /**
907  * Pivot the rows, creating a new resultset
908  *
909  * Call dbpivot() immediately after dbresults(). It calls dbnextrow() as long as
910  * it returns REG_ROW, transforming the results into a cross-tab report.
911  * dbpivot() modifies the metadata such that DB-Library can be used tranparently:
912  * retrieve the rows as usual with dbnumcols(), dbnextrow(), etc.
913  *
914  * @dbproc, our old friend
915  * @nkeys the number of left-edge columns to group by
916  * @keys an array of left-edge columns to group by
917  * @ncols the number of top-edge columns to group by
918  * @cols an array of top-edge columns to group by
919  * @func the aggregation function to use
920  * @val the number of the column to which @func is applied
921  *
922  * @returns the return code from the final call to dbnextrow().
923  * Success is normally indicated by NO_MORE_ROWS.
924  */
925 RETCODE
926 dbpivot(DBPROCESS *dbproc, int nkeys, int *keys, int ncols, int *cols, DBPIVOT_FUNC func, int val)
927 {
928  enum { logalot = 1 };
929  PIVOT_T P, *pp;
930  AGG_T input, *pout = NULL;
931  struct metadata_t *metadata, *pmeta;
932  int i;
933  TDS_USMALLINT nmeta = 0;
934 
935  tdsdump_log(TDS_DBG_FUNC, "dbpivot(%p, %d,%p, %d,%p, %p, %d)\n", dbproc, nkeys, keys, ncols, cols, func, val);
936  if (logalot) {
937  char buffer[1024] = {'\0'}, *s = buffer;
938  const static char *const names[2] = { "\tkeys (down)", "\n\tcols (across)" };
939  int *p = keys, *pend = p + nkeys;
940 
941  for (i=0; i < 2; i++) {
942  const char *sep = "";
943  s += sprintf(s, "%s: ", names[i]);
944  for ( ; p < pend; p++) {
945  s += sprintf(s, "%s%d", sep, *p);
946  sep = ", ";
947  }
948  p = cols;
949  pend = p + ncols;
950  assert(s < buffer + sizeof(buffer));
951  }
952  tdsdump_log(TDS_DBG_FUNC, "%s\n", buffer);
953  }
954 
955  memset(&input, 0, sizeof(input));
956 
957  P.dbproc = dbproc;
958  if ((pp = (PIVOT_T *) tds_find(&P, pivots, npivots, sizeof(*pivots),
960  == NULL) {
961  pp = (PIVOT_T *) TDS_RESIZE(pivots, 1 + npivots);
962  if (!pp)
963  return FAIL;
964  pp += npivots++;
965  } else {
966  agg_free(pp->output);
967  key_free(pp->across);
968  }
969  memset(pp, 0, sizeof(*pp));
970 
971  if ((input.row_key.keys = tds_new0(struct col_t, nkeys)) == NULL)
972  return FAIL;
973  input.row_key.nkeys = nkeys;
974  for (i=0; i < nkeys; i++) {
975  int type = dbcoltype(dbproc, keys[i]);
976  int len = dbcollen(dbproc, keys[i]);
977  assert(type && len);
978 
979  if (!col_init(input.row_key.keys+i, type, len))
980  return FAIL;
981  if (FAIL == dbbind(dbproc, keys[i], bind_type(type),
982  (DBINT) input.row_key.keys[i].len,
983  (BYTE *) col_buffer(input.row_key.keys+i)))
984  return FAIL;
985  if (FAIL == dbnullbind(dbproc, keys[i], &input.row_key.keys[i].null_indicator))
986  return FAIL;
987  }
988 
989  if ((input.col_key.keys = tds_new0(struct col_t, ncols)) == NULL)
990  return FAIL;
991  input.col_key.nkeys = ncols;
992  for (i=0; i < ncols; i++) {
993  int type = dbcoltype(dbproc, cols[i]);
994  int len = dbcollen(dbproc, cols[i]);
995  assert(type && len);
996 
997  if (!col_init(input.col_key.keys+i, type, len))
998  return FAIL;
999  if (FAIL == dbbind(dbproc, cols[i], bind_type(type),
1000  (DBINT) input.col_key.keys[i].len,
1001  (BYTE *) col_buffer(input.col_key.keys+i)))
1002  return FAIL;
1003  if (FAIL == dbnullbind(dbproc, cols[i], &input.col_key.keys[i].null_indicator))
1004  return FAIL;
1005  }
1006 
1007  /* value */ {
1008  int type = dbcoltype(dbproc, val);
1009  int len = dbcollen(dbproc, val);
1010  assert(type && len);
1011 
1012  if (!col_init(&input.value, type, len))
1013  return FAIL;
1014  if (FAIL == dbbind(dbproc, val, bind_type(type),
1015  input.value.len,
1016  (BYTE *) col_buffer(&input.value)))
1017  return FAIL;
1018  if (FAIL == dbnullbind(dbproc, val, &input.value.null_indicator))
1019  return FAIL;
1020  }
1021 
1022  while ((pp->status = dbnextrow(dbproc)) == REG_ROW) {
1023  /* add to unique list of crosstab columns */
1024  if ((AGG_T *) tds_find(&input.col_key, pp->across, pp->nacross,
1025  sizeof(*pp->across),
1027  == NULL) {
1028  if (!TDS_RESIZE(pp->across, 1 + pp->nacross))
1029  return FAIL;
1030  key_cpy(pp->across + pp->nacross, &input.col_key);
1031  }
1032  assert(pp->across);
1033 
1034  if ((pout = tds_find(&input, pp->output, pp->nout, sizeof(*pp->output), (compare_func) agg_equal)) == NULL ) {
1035  if (!TDS_RESIZE(pp->output, 1 + pp->nout))
1036  return FAIL;
1037  pout = pp->output + pp->nout++;
1038 
1039 
1040  if ((pout->row_key.keys = tds_new0(struct col_t, input.row_key.nkeys)) == NULL)
1041  return FAIL;
1042  key_cpy(&pout->row_key, &input.row_key);
1043 
1044  if ((pout->col_key.keys = tds_new0(struct col_t, input.col_key.nkeys)) == NULL)
1045  return FAIL;
1046  key_cpy(&pout->col_key, &input.col_key);
1047 
1048  if (!col_init(&pout->value, input.value.type, input.value.len))
1049  return FAIL;
1050  }
1051 
1052  func(&pout->value, &input.value);
1053 
1054  }
1055 
1056  /* Mark this proc as pivoted, so that dbnextrow() sees it when the application calls it */
1057  pp->dbproc = dbproc;
1060 
1061  /*
1062  * Initialize new metadata
1063  */
1064  nmeta = input.row_key.nkeys + pp->nacross;
1065  metadata = tds_new0(struct metadata_t, nmeta);
1066  if (!metadata) {
1067  dbperror(dbproc, SYBEMEM, errno);
1068  return FAIL;
1069  }
1070  assert(pp->across || pp->nacross == 0);
1071 
1072  /* key columns are passed through as-is, verbatim */
1073  for (i=0; i < input.row_key.nkeys; i++) {
1074  assert(i < nkeys);
1075  metadata[i].name = strdup(dbcolname(dbproc, keys[i]));
1076  metadata[i].pacross = NULL;
1077  col_cpy(&metadata[i].col, input.row_key.keys+i);
1078  }
1079 
1080  /* pivoted columms are found in the "across" data */
1081  for (i=0, pmeta = metadata + input.row_key.nkeys; i < pp->nacross; i++) {
1082  struct col_t col;
1083  if (!col_init(&col, SYBFLT8, sizeof(double)))
1084  return FAIL;
1085  assert(pmeta + i < metadata + nmeta);
1086  pmeta[i].name = make_col_name(dbproc, pp->across+i);
1087  if (!pmeta[i].name)
1088  return FAIL;
1089  assert(pp->across);
1090  pmeta[i].pacross = pp->across + i;
1091  col_cpy(&pmeta[i].col, pp->nout? &pp->output[0].value : &col);
1092  }
1093 
1094  if (!reinit_results(dbproc->tds_socket, nmeta, metadata)) {
1095  return FAIL;
1096  }
1097 
1098  return SUCCEED;
1099 
1100 #if 0
1101  for (pp->pout=pp->output; pp->pout < pp->output + pp->nout; pp->pout++) {
1102  char name[256] = {0};
1103 
1104  assert(pp->pout->col_key.keys[0].len < sizeof(name));
1105  memset(name, '\0', sizeof(name));
1106  memcpy(name, pp->pout->col_key.keys[0].s, pp->pout->col_key.keys[0].len),
1107  tdsdump_log(TDS_DBG_FUNC, "%5d %-30s %5d\n",
1108  pp->pout->row_key.keys[0].i, name,
1109  pp->pout->value.i );
1110  }
1111  exit(1);
1112 #endif
1113 }
1114 
1115 /*
1116  * Aggregation functions
1117  */
1118 
1119 void
1120 dbpivot_count (struct col_t *tgt, const struct col_t *src)
1121 {
1122  assert( tgt && src);
1123  assert (src->type);
1124 
1125  tgt->type = SYBINT4;
1126 
1127  if (! col_null(src))
1128  tgt->data.i++;
1129 }
1130 
1131 void
1132 dbpivot_sum (struct col_t *tgt, const struct col_t *src)
1133 {
1134  assert( tgt && src);
1135  assert (src->type);
1136 
1137  tgt->type = src->type;
1138 
1139  if (col_null(src))
1140  return;
1141 
1142  switch (src->type) {
1143  case SYBINT1:
1144  tgt->data.ti += src->data.ti;
1145  break;
1146  case SYBINT2:
1147  tgt->data.si += src->data.si;
1148  break;
1149  case SYBINT4:
1150  tgt->data.i += src->data.i;
1151  break;
1152  case SYBFLT8:
1153  tgt->data.f += src->data.f;
1154  break;
1155  case SYBREAL:
1156  tgt->data.r += src->data.r;
1157  break;
1158 
1159  case SYBCHAR:
1160  case SYBVARCHAR:
1161  case SYBINTN:
1162  case SYBDATETIME:
1163  case SYBBIT:
1164  case SYBTEXT:
1165  case SYBNTEXT:
1166  case SYBIMAGE:
1167  case SYBMONEY4:
1168  case SYBMONEY:
1169  case SYBDATETIME4:
1170  case SYBBINARY:
1171  case SYBVOID:
1172  case SYBVARBINARY:
1173  case SYBBITN:
1174  case SYBNUMERIC:
1175  case SYBDECIMAL:
1176  case SYBFLTN:
1177  case SYBMONEYN:
1178  case SYBDATETIMN:
1179  default:
1180  tdsdump_log(TDS_DBG_INFO1, "dbpivot_sum(): invalid operand %d\n", src->type);
1181  tgt->type = SYBINT4;
1182  tgt->data.i = 0;
1183  break;
1184  }
1185 }
1186 
1187 void
1188 dbpivot_min (struct col_t *tgt, const struct col_t *src)
1189 {
1190  assert( tgt && src);
1191  assert (src->type);
1192 
1193  tgt->type = src->type;
1194 
1195  if (col_null(src))
1196  return;
1197 
1198  switch (src->type) {
1199  case SYBINT1:
1200  tgt->data.ti = tgt->data.ti < src->data.ti? tgt->data.ti : src->data.ti;
1201  break;
1202  case SYBINT2:
1203  tgt->data.si = tgt->data.si < src->data.si? tgt->data.si : src->data.si;
1204  break;
1205  case SYBINT4:
1206  tgt->data.i = tgt->data.i < src->data.i? tgt->data.i : src->data.i;
1207  break;
1208  case SYBFLT8:
1209  tgt->data.f = tgt->data.f < src->data.f? tgt->data.f : src->data.f;
1210  break;
1211  case SYBREAL:
1212  tgt->data.r = tgt->data.r < src->data.r? tgt->data.r : src->data.r;
1213  break;
1214 
1215  case SYBCHAR:
1216  case SYBVARCHAR:
1217  case SYBINTN:
1218  case SYBDATETIME:
1219  case SYBBIT:
1220  case SYBTEXT:
1221  case SYBNTEXT:
1222  case SYBIMAGE:
1223  case SYBMONEY4:
1224  case SYBMONEY:
1225  case SYBDATETIME4:
1226  case SYBBINARY:
1227  case SYBVOID:
1228  case SYBVARBINARY:
1229  case SYBBITN:
1230  case SYBNUMERIC:
1231  case SYBDECIMAL:
1232  case SYBFLTN:
1233  case SYBMONEYN:
1234  case SYBDATETIMN:
1235  default:
1236  tdsdump_log(TDS_DBG_INFO1, "dbpivot_sum(): invalid operand %d\n", src->type);
1237  tgt->type = SYBINT4;
1238  tgt->data.i = 0;
1239  break;
1240  }
1241 }
1242 
1243 void
1244 dbpivot_max (struct col_t *tgt, const struct col_t *src)
1245 {
1246  assert( tgt && src);
1247  assert (src->type);
1248 
1249  tgt->type = src->type;
1250 
1251  if (col_null(src))
1252  return;
1253 
1254  switch (src->type) {
1255  case SYBINT1:
1256  tgt->data.ti = tgt->data.ti > src->data.ti? tgt->data.ti : src->data.ti;
1257  break;
1258  case SYBINT2:
1259  tgt->data.si = tgt->data.si > src->data.si? tgt->data.si : src->data.si;
1260  break;
1261  case SYBINT4:
1262  tgt->data.i = tgt->data.i > src->data.i? tgt->data.i : src->data.i;
1263  break;
1264  case SYBFLT8:
1265  tgt->data.f = tgt->data.f > src->data.f? tgt->data.f : src->data.f;
1266  break;
1267  case SYBREAL:
1268  tgt->data.r = tgt->data.r > src->data.r? tgt->data.r : src->data.r;
1269  break;
1270 
1271  case SYBCHAR:
1272  case SYBVARCHAR:
1273  case SYBINTN:
1274  case SYBDATETIME:
1275  case SYBBIT:
1276  case SYBTEXT:
1277  case SYBNTEXT:
1278  case SYBIMAGE:
1279  case SYBMONEY4:
1280  case SYBMONEY:
1281  case SYBDATETIME4:
1282  case SYBBINARY:
1283  case SYBVOID:
1284  case SYBVARBINARY:
1285  case SYBBITN:
1286  case SYBNUMERIC:
1287  case SYBDECIMAL:
1288  case SYBFLTN:
1289  case SYBMONEYN:
1290  case SYBDATETIMN:
1291  default:
1292  tdsdump_log(TDS_DBG_INFO1, "dbpivot_sum(): invalid operand %d\n", src->type);
1293  tgt->type = SYBINT4;
1294  tgt->data.i = 0;
1295  break;
1296  }
1297 }
1298 
1299 static const struct name_t {
1300  char name[14];
1302 } names[] =
1303  { { "count", dbpivot_count }
1304  , { "sum", dbpivot_sum }
1305  , { "min", dbpivot_min }
1306  , { "max", dbpivot_max }
1307  };
1308 
1309 static bool
1310 name_equal( const struct name_t *n1, const struct name_t *n2 )
1311 {
1312  assert(n1 && n2);
1313  return strcmp(n1->name, n2->name) == 0;
1314 }
1315 
1316 DBPIVOT_FUNC
1317 dbpivot_lookup_name( const char name[] )
1318 {
1320 
1321  return n ? n->func : NULL;
1322 }
#define true
Definition: bool.h:35
#define bool
Definition: bool.h:34
static TDSSOCKET * tds
Definition: collations.c:37
static const char pc1[]
Definition: des.c:116
static const char pc2[]
Definition: des.c:134
STATUS dbnextrow(DBPROCESS *dbproc)
Definition: dblib.c:2076
@ _DB_RES_NEXT_RESULT
Definition: dblib.h:37
@ _DB_RES_RESULTSET_EMPTY
Definition: dblib.h:35
@ _DB_RES_RESULTSET_ROWS
Definition: dblib.h:36
enum tag_DB_RESULT_STATE DB_RESULT_STATE
#define tds_alloc_column()
Definition: dbpivot.c:654
struct pivot_t PIVOT_T
static bool col_equal(const struct col_t *pc1, const struct col_t *pc2)
Definition: dbpivot.c:132
static bool name_equal(const struct name_t *n1, const struct name_t *n2)
Definition: dbpivot.c:1310
static struct col_t * col_init(struct col_t *pcol, int sybtype, size_t collen)
Definition: dbpivot.c:93
bool(* compare_func)(const void *, const void *)
Definition: dbpivot.c:58
static bool col_null(const struct col_t *pcol)
Definition: dbpivot.c:295
static TDS_SERVER_TYPE infer_col_type(int sybtype)
Definition: dbpivot.c:381
void dbpivot_count(struct col_t *tgt, const struct col_t *src)
Definition: dbpivot.c:1120
static bool key_equal(const KEY_T *a, const KEY_T *b)
Definition: dbpivot.c:472
static TDSRET set_result_column(TDSSOCKET *tds, TDSCOLUMN *curcol, const char name[], const struct col_t *pvalue)
Definition: dbpivot.c:679
static size_t npivots
Definition: dbpivot.c:796
struct agg_t AGG_T
static const struct name_t names[]
static void * tds_find(const void *key, const void *base, size_t nelem, size_t width, compare_func compar)
Definition: dbpivot.c:61
static PIVOT_T * pivots
Definition: dbpivot.c:795
static struct col_t * col_cpy(struct col_t *pdest, const struct col_t *psrc)
Definition: dbpivot.c:276
static char * join(int argc, char *argv[], const char sep[])
Definition: dbpivot.c:359
#define TEST_CALLOC(dest, type, n)
Definition: dbpivot.c:651
static KEY_T * key_cpy(KEY_T *pdest, const KEY_T *psrc)
Definition: dbpivot.c:497
static void agg_free(AGG_T *p)
Definition: dbpivot.c:615
static void col_free(struct col_t *p)
Definition: dbpivot.c:125
PIVOT_T * dbrows_pivoted(DBPROCESS *dbproc)
Definition: dbpivot.c:799
static bool reinit_results(TDSSOCKET *tds, TDS_USMALLINT num_cols, const struct metadata_t meta[])
Definition: dbpivot.c:720
#define TEST_MALLOC(dest, type)
Definition: dbpivot.c:647
DBPIVOT_FUNC dbpivot_lookup_name(const char name[])
Definition: dbpivot.c:1317
void dbpivot_min(struct col_t *tgt, const struct col_t *src)
Definition: dbpivot.c:1188
STATUS dbnextrow_pivoted(DBPROCESS *dbproc, PIVOT_T *pp)
Definition: dbpivot.c:810
static bool pivot_key_equal(const PIVOT_T *a, const PIVOT_T *b)
Definition: dbpivot.c:788
static bool agg_next(const AGG_T *p1, const AGG_T *p2)
Definition: dbpivot.c:574
static TDSRESULTINFO * alloc_results(TDS_USMALLINT num_cols)
Definition: dbpivot.c:657
static bool agg_equal(const AGG_T *p1, const AGG_T *p2)
Definition: dbpivot.c:623
struct KEY_T KEY_T
void dbpivot_max(struct col_t *tgt, const struct col_t *src)
Definition: dbpivot.c:1244
static char * string_value(const struct col_t *pcol)
Definition: dbpivot.c:302
#define TDS_FIND(k, b, c)
Definition: dbpivot.c:56
void dbpivot_sum(struct col_t *tgt, const struct col_t *src)
Definition: dbpivot.c:1132
static int bind_type(int sybtype)
Definition: dbpivot.c:424
static char * make_col_name(DBPROCESS *dbproc, const KEY_T *k)
Definition: dbpivot.c:518
static void * col_buffer(struct col_t *pcol)
Definition: dbpivot.c:183
static void key_free(KEY_T *p)
Definition: dbpivot.c:489
RETCODE dbpivot(DBPROCESS *dbproc, int nkeys, int *keys, int ncols, int *cols, DBPIVOT_FUNC func, int val)
Pivot the rows, creating a new resultset.
Definition: dbpivot.c:926
std::ofstream out("events_result.xml")
main entry point for tests
#define NULL
Definition: ncbistd.hpp:225
int dbcoltype(DBPROCESS *dbproc, int column)
Get the datatype of a regular result set column.
Definition: dblib.c:2902
RETCODE dbnullbind(DBPROCESS *dbproc, int column, DBINT *indicator)
Tie a null-indicator to a regular result column.
Definition: dblib.c:2751
RETCODE dbbind(DBPROCESS *dbproc, int column, int vartype, DBINT varlen, BYTE *varaddr)
Tie a host variable to a resultset column.
Definition: dblib.c:2645
DBINT dbcollen(DBPROCESS *dbproc, int column)
Get size of a regular result column.
Definition: dblib.c:3109
char * dbcolname(DBPROCESS *dbproc, int column)
Return name of a regular result column.
Definition: dblib.c:1884
static const char * tds_dstr_cstr(DSTR *s)
Returns a C version (NUL terminated string) of dstr.
Definition: string.h:66
DSTR * tds_dstr_copy(DSTR *s, const char *src) TDS_WUR
copy a string from another
Definition: tdsstring.c:123
exit(2)
static int input()
int i
yy_size_t n
int len
#define P(a, b, c, d, k, s, t)
static MDB_envinfo info
Definition: mdb_load.c:37
const struct ncbi::grid::netcache::search::fields::KEY key
int strncmp(const char *str1, const char *str2, size_t count)
Definition: odbc_utils.hpp:133
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define strdup
Definition: ncbi_ansi_ext.h:70
unsigned int a
Definition: ncbi_localip.c:102
static pcre_uint8 * buffer
Definition: pcretest.c:1051
static SQLCHAR output[256]
Definition: print.c:5
#define TDS_UT_TIMESTAMP
Definition: proto.h:385
TDS_SERVER_TYPE
Definition: proto.h:161
#define dbgetnull
#define copy_data_to_host_var
#define dbperror
#define tds_set_column_type
#define tds_free_all_results
#define tds_prtype
#define tds_set_current_results
#define tds_alloc_row
#define tds_free_results
#define asprintf
Definition: replacements.h:54
#define strcat(s, k)
#define assert(x)
Definition: srv_diag.hpp:58
Definition: dbpivot.c:466
struct col_t * keys
Definition: dbpivot.c:468
int nkeys
Definition: dbpivot.c:467
Definition: dbpivot.c:548
KEY_T col_key
Definition: dbpivot.c:549
KEY_T row_key
Definition: dbpivot.c:549
struct col_t value
Definition: dbpivot.c:550
Definition: dbpivot.c:76
char * s
Definition: dbpivot.c:80
DBFLT8 f
Definition: dbpivot.c:86
DBREAL r
Definition: dbpivot.c:85
int null_indicator
Definition: dbpivot.c:79
size_t len
Definition: dbpivot.c:77
DBINT i
Definition: dbpivot.c:84
union col_t::@976 data
DBSMALLINT si
Definition: dbpivot.c:83
DBTINYINT ti
Definition: dbpivot.c:82
TDS_SERVER_TYPE type
Definition: dbpivot.c:78
KEY_T * pacross
Definition: dbpivot.c:716
char * name
Definition: dbpivot.c:716
struct col_t col
Definition: dbpivot.c:716
char name[14]
Definition: dbpivot.c:1300
DBPIVOT_FUNC func
Definition: dbpivot.c:1301
TDS_USMALLINT nacross
Definition: dbpivot.c:784
KEY_T * across
Definition: dbpivot.c:782
DB_RESULT_STATE dbresults_state
Definition: dbpivot.c:779
STATUS status
Definition: dbpivot.c:778
AGG_T * output
Definition: dbpivot.c:781
size_t nout
Definition: dbpivot.c:783
DBPROCESS * dbproc
Definition: dbpivot.c:777
tds_func_get_info * get_info
Definition: tds.h:710
Metadata about columns in regular and compute rows.
Definition: tds.h:761
TDS_CHAR * bcp_terminator
Definition: tds.h:836
TDS_TINYINT column_varint_size
size of length when reading from wire (0, 1, 2 or 4)
Definition: tds.h:773
TDS_SMALLINT * column_nullbind
Definition: tds.h:818
TDS_INT column_size
maximun size of data.
Definition: tds.h:766
DSTR column_name
Definition: tds.h:787
unsigned int column_timestamp
Definition: tds.h:801
TDS_UINT column_bindlen
Definition: tds.h:817
const TDSCOLUMNFUNCS * funcs
Definition: tds.h:762
TDS_SMALLINT column_bindtype
Definition: tds.h:815
unsigned int column_writeable
Definition: tds.h:796
unsigned char * column_data
Definition: tds.h:793
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:768
unsigned int column_identity
Definition: tds.h:797
unsigned int column_nullable
Definition: tds.h:795
TDS_CHAR * column_varaddr
Definition: tds.h:819
struct tds_column::@124 on_server
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:811
TDS_INT column_usertype
Definition: tds.h:763
TDSRESULTINFO * res_info
Definition: tds.h:1025
TDSSOCKET * tds_socket
Definition: dblib.h:122
DB_RESULT_STATE dbresults_state
Definition: dblib.h:129
Hold information for any results.
Definition: tds.h:842
TDS_USMALLINT num_cols
Definition: tds.h:845
TDS_INT ref_count
Definition: tds.h:847
TDSCOLUMN ** columns
Definition: tds.h:844
TDS_INT row_size
Definition: tds.h:851
Information for a server connection.
Definition: tds.h:1211
TDSRESULTINFO * res_info
Definition: tds.h:1264
TDS_INT8 rows_affected
rows updated/deleted/inserted/selected, TDS_NO_COUNT if not valid
Definition: tds.h:1278
TDSCURSOR * cur_cursor
cursor in use
Definition: tds.h:1268
TDSCONNECTION conn[1]
Definition: tds.h:1215
Definition: type.c:6
int STATUS
Definition: sybdb.h:148
#define SYBVOID
Definition: sybdb.h:198
#define SYBINT4
Definition: sybdb.h:170
#define REG_ROW
Definition: sybdb.h:580
#define SYBEMEM
Definition: sybdb.h:938
#define FLT8BIND
Definition: sybdb.h:555
#define SYBNUMERIC
Definition: sybdb.h:202
#define SYBVARCHAR
Definition: sybdb.h:162
int RETCODE
Definition: sybdb.h:121
#define SYBTEXT
Definition: sybdb.h:182
#define SMALLBIND
Definition: sybdb.h:553
#define NTBSTRINGBIND
Definition: sybdb.h:549
unsigned char BYTE
Definition: sybdb.h:334
#define NO_MORE_ROWS
Definition: sybdb.h:582
#define SYBMONEYN
Definition: sybdb.h:208
double DBFLT8
Definition: sybdb.h:259
#define SYBNTEXT
Definition: sybdb.h:184
#define SYBIMAGE
Definition: sybdb.h:186
#define SYBINTN
Definition: sybdb.h:164
Int2 DBSMALLINT
Definition: sybdb.h:254
#define SYBINT1
Definition: sybdb.h:166
#define SYBDATETIME4
Definition: sybdb.h:192
#define SYBDECIMAL
Definition: sybdb.h:204
#define INTBIND
Definition: sybdb.h:554
#define SUCCEED
Definition: sybdb.h:585
#define SYBCHAR
Definition: sybdb.h:160
#define SYBREAL
Definition: sybdb.h:194
#define SYBDATETIMN
Definition: sybdb.h:210
#define SYBBITN
Definition: sybdb.h:180
void(* DBPIVOT_FUNC)(struct col_t *output, const struct col_t *input)
Definition: sybdb.h:841
#define SYBBINARY
Definition: sybdb.h:196
#define REALBIND
Definition: sybdb.h:556
unsigned char DBTINYINT
Definition: sybdb.h:253
#define FAIL
Definition: sybdb.h:586
float DBREAL
Definition: sybdb.h:258
#define SYBDATETIME
Definition: sybdb.h:176
#define SYBVARBINARY
Definition: sybdb.h:200
#define SYBMONEY
Definition: sybdb.h:190
#define SYBMONEY4
Definition: sybdb.h:188
#define SYBFLT8
Definition: sybdb.h:174
#define SYBFLTN
Definition: sybdb.h:206
Int4 DBINT
Definition: sybdb.h:255
#define TINYBIND
Definition: sybdb.h:552
#define SYBINT2
Definition: sybdb.h:168
#define SYBBIT
Definition: sybdb.h:178
DBPROCESS * dbproc
Definition: t0013.c:18
Main include file for libtds.
#define TDS_FAIL
Definition: tds.h:204
#define tds_new(type, n)
Definition: tds.h:1392
#define TDS_NO_COUNT
Definition: tds.h:214
#define TDS_FAILED(rc)
Definition: tds.h:206
#define tdsdump_log
Definition: tds.h:1561
#define TDS_INVALID_TYPE
Definition: tds.h:160
#define TDS_DBG_INFO1
Definition: tds.h:900
#define tds_new0(type, n)
Definition: tds.h:1393
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_DBG_ERROR
Definition: tds.h:903
#define TDS_SUCCESS
Definition: tds.h:203
#define TDS_RESIZE(p, n_elem)
Definition: tds.h:1390
#define TDS_DBG_FUNC
Definition: tds.h:898
void free(voidpf ptr)
Modified on Sat Dec 02 09:23:01 2023 by modify_doxy.py rev. 669887