LCOV - code coverage report
Current view: top level - src/dblib - dbpivot.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 6 472 1.3 %
Date: 2025-02-21 10:02:42 Functions: 1 29 3.4 %

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

Generated by: LCOV version 1.13