1 /**
2 Copyright (C) 1995, 1996 by Ke Jin <kejin@visigenic.com>
3 Enhanced for unixODBC (1999) by Peter Harvey <pharvey@codebydesign.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 **/
15 #include <config.h>
16 #include "driver.h"
17
18 static char sccsid[]
19 = "@(#)NNSQL(NetNews SQL) v0.5, Copyright(c) 1995, 1996 by Ke Jin";
20
21 static int yyunbindpar(yystmt_t* yystmt, int ipar);
22
nnsql_allocyystmt(void * hcndes)23 void* nnsql_allocyystmt(void* hcndes)
24 {
25 yystmt_t* yystmt;
26
27 yystmt = (yystmt_t*)MEM_ALLOC(sizeof(yystmt_t));
28
29 if( ! yystmt )
30 return 0;
31
32 MEM_SET(yystmt, 0, sizeof(yystmt_t));
33
34 yystmt->hcndes = hcndes;
35
36 return yystmt;
37 }
38
nnsql_close_cursor(void * hstmt)39 void nnsql_close_cursor(void* hstmt)
40 {
41 yystmt_t* yystmt = hstmt;
42 yyattr_t* pattr;
43 int i;
44
45 if( !hstmt )
46 return;
47
48 for(pattr = yystmt->pattr, i=0; pattr && i<=en_body; pattr++, i++)
49 {
50 pattr->stat = 0; /* not needed */
51 pattr->wstat= 0;
52 nntp_closeheader(pattr->nntp_hand);
53 pattr->nntp_hand = 0;
54 }
55 }
56
nnsql_dropyystmt(void * hstmt)57 void nnsql_dropyystmt(void* hstmt)
58 {
59 yystmt_t* yystmt = hstmt;
60 int i;
61
62 if(! hstmt )
63 return;
64
65 /* allocated for any statement
66 */
67 MEM_FREE( yystmt->texts_buf );
68 MEM_FREE( yystmt->sqlexpr );
69
70 /* allocated for SELECT statement
71 */
72 MEM_FREE( yystmt->node_buf );
73 MEM_FREE( yystmt->pcol );
74
75 nnsql_close_cursor(hstmt);
76
77 if( yystmt->pattr )
78 {
79 MEM_FREE( (yystmt->pattr)[en_body].value.location );
80 MEM_FREE( yystmt->pattr );
81 }
82
83 /* allocated for yybindpar(). i.e. nnsql_put{date, str, num}()
84 */
85 for(i=1;;i++)
86 {
87 if( yyunbindpar(yystmt, i) )
88 break;
89 }
90 MEM_FREE( yystmt->ppar );
91
92 /* allocated for INSERT statement
93 */
94 MEM_FREE( yystmt->ins_heads );
95 MEM_FREE( yystmt->ins_values);
96
97 /* the statement object itself
98 */
99 MEM_FREE( hstmt );
100 }
101
nnsql_resetyystmt(void * hstmt)102 static void nnsql_resetyystmt(void* hstmt)
103 {
104 yystmt_t* yystmt = hstmt;
105 int i;
106
107 if( ! hstmt )
108 return;
109
110 yystmt->type = en_stmt_alloc;
111
112 /* clear result from any statement
113 */
114 MEM_FREE( yystmt->sqlexpr );
115 MEM_FREE( yystmt->texts_buf );
116 yystmt->sqlexpr = 0;
117 yystmt->texts_buf = 0;
118
119 yystmt->table = 0;
120
121 yystmt->ncol = 0;
122 yystmt->npar = 0;
123 yystmt->count = 0;
124
125 /* reset the search tree (but not free the buffer of it)
126 */
127 yystmt->srchtree = 0;
128 yystmt->srchtreenum = 0;
129
130 /* clear fetched result
131 */
132 nnsql_close_cursor(hstmt);
133
134 /* clear result of bindpar()
135 */
136 for(i=1; ;i++ )
137 {
138 if( yyunbindpar(yystmt, i) )
139 break;
140 }
141
142 /* clear result of insert statement
143 */
144 MEM_FREE( yystmt->ins_heads );
145 MEM_FREE( yystmt->ins_values );
146 yystmt->ins_heads = 0;
147 yystmt->ins_values= 0;
148 }
149
yyfetch(void * hstmt,int wstat)150 static int yyfetch(void* hstmt, int wstat)
151 {
152 int i, j, nattr;
153 yystmt_t* yystmt = hstmt;
154
155 if( ! hstmt || ! yystmt->pattr )
156 return -1;
157
158 for(i=en_article_num + 1, nattr=0; i<= en_body; i++)
159 {
160 yyattr_t* pattr;
161 yyattr_t* tpattr;
162 void* hrh = 0;
163
164 pattr = yystmt->pattr + i;
165
166 if(i == en_body )
167 {
168 if( nattr )
169 break;
170
171 i = en_lines; /* use lines to retrive article number */
172 pattr = yystmt->pattr;
173 nattr --;
174 }
175
176 if( pattr->stat && pattr->wstat == wstat )
177 {
178 char* header;
179 long data;
180 int r;
181
182 nattr++;
183
184 if( ! (header = nnsql_getcolnamebyidx(i)) )
185 return -1;
186
187 if( !wstat && !hrh )
188 {
189 for(j = 0, tpattr = yystmt->pattr;
190 j < en_body;
191 j++)
192 {
193 tpattr++;
194
195 if( tpattr->wstat )
196 {
197 hrh = tpattr->nntp_hand;
198 break;
199 }
200 }
201
202 if( !hrh && yystmt->pattr->wstat )
203 hrh = yystmt->pattr->nntp_hand;
204 }
205
206 if( ! pattr->nntp_hand )
207 {
208 nnsql_getrange(yystmt, &(yystmt->artnum_min), &(yystmt->artnum_max));
209
210 pattr->nntp_hand =
211 nntp_openheader( yystmt->hcndes, header,
212 &(yystmt->artnum_min), &(yystmt->artnum_max) );
213
214 if( ! pattr->nntp_hand )
215 return -1;
216 }
217
218 if( yystmt->artnum_max )
219 r = nntp_fetchheader( pattr->nntp_hand,
220 &((yystmt->pattr->value).number), &data, hrh );
221 else
222 r = 100;
223
224 if( !r && !i )
225 {
226 data = (yystmt->pattr->value).number;
227 if(data > yystmt->artnum_max)
228 r = 100;
229 }
230
231 switch(r)
232 {
233 case 100:
234 (yystmt->pattr->value).number = 0;
235 case -1:
236 nntp_closeheader(pattr->nntp_hand);
237 pattr->nntp_hand = 0;
238 return r;
239
240 case 0:
241 break;
242
243 default:
244 abort();
245 break;
246 }
247
248 switch(i)
249 {
250 case en_lines:
251 if( nattr )
252 (pattr->value).number = (long)(data);
253 else
254 return 0;
255 break;
256
257 case en_date:
258 nnsql_nndatestr2date((char*)data,
259 &((pattr->value).date) );
260 break;
261
262 default:
263 (pattr->value).location = (char*)(data);
264 break;
265 }
266 }
267 }
268
269 return 0;
270 }
271
272 #include <stdio.h>
273
nnsql_fetch(void * hstmt)274 int nnsql_fetch(void* hstmt)
275 {
276 int r, i;
277 yystmt_t* pstmt = hstmt;
278 yyattr_t* pattr = pstmt->pattr + en_body;
279
280 for(;;)
281 {
282 switch( pstmt->type )
283 {
284 case en_stmt_fetch_count:
285 pstmt->type = en_stmt_alloc;
286 return 100;
287
288 case en_stmt_select:
289 break;
290
291 default:
292 return -1;
293 }
294
295 r = yyfetch(hstmt, 1);
296
297 switch(r)
298 {
299 case 100:
300 for(i=1; i<pstmt->ncol; i++)
301 {
302 if( (pstmt->pcol + i)->iattr == en_sql_count )
303 {
304 pstmt->type = en_stmt_fetch_count;
305 return 0;
306 }
307 }
308 pstmt->type = en_stmt_alloc;
309 return 100;
310
311 case -1:
312 pstmt->type = en_stmt_alloc;
313 return -1;
314
315 case 0:
316 r = nnsql_srchtree_evl(hstmt);
317
318 switch(r)
319 {
320 case -1:
321 pstmt->type = en_stmt_alloc;
322 return r;
323
324 case 1:
325 pstmt->count++;
326
327 if( pstmt->ncol == 2
328 && (pstmt->pcol + 1)->iattr == en_sql_count )
329 continue;
330
331 if( (r = yyfetch(hstmt, 0)) == -1 )
332 {
333 pstmt->type = en_stmt_alloc;
334 return -1;
335 }
336
337 if( pattr->stat )
338 /* pattr has already init to point
339 * to the en_body attr
340 */
341 {
342 MEM_FREE( (pattr->value).location );
343
344 (pattr->value).location =
345 nntp_body( pstmt->hcndes,
346 (pstmt->pattr->value).number, 0);
347 }
348 return 0;
349
350 case 0:
351 continue;
352
353 default:
354 abort();
355 break;
356 }
357 break;
358
359 default:
360 abort();
361 break;
362 }
363
364 break;
365 }
366
367 abort();
368
369 return -1;
370 }
371
nnsql_opentable(void * hstmt,char * table)372 int nnsql_opentable(void* hstmt, char* table)
373 {
374 yystmt_t* yystmt = hstmt;
375
376 if(! hstmt )
377 return -1;
378
379 if( !table )
380 table = yystmt->table;
381
382 return nntp_group( yystmt->hcndes, table );
383 }
384
nnsql_yyunbindpar(void * yystmt,int ipar)385 int nnsql_yyunbindpar(void* yystmt, int ipar)
386 {
387 return yyunbindpar(yystmt, ipar);
388 }
389
yyunbindpar(yystmt_t * yystmt,int ipar)390 static int yyunbindpar(yystmt_t* yystmt, int ipar)
391 {
392 int i;
393 yypar_t* par;
394
395 if( yystmt
396 || ipar <= 0
397 || ipar > MAX_PARAM_NUMBER
398 || yystmt->ppar )
399 return -1;
400
401 par = yystmt->ppar + ipar - 1;
402
403 switch( par->type )
404 {
405 case -1:
406 case en_nt_num:
407 case en_nt_null:
408 break;
409
410 case en_nt_qstr:
411 MEM_FREE( par->value.location );
412 break;
413
414 default:
415 abort();
416 break;
417 }
418
419 yystmt->ppar->type = -1;
420 return 0;
421 }
422
yybindpar(yystmt_t * yystmt,int ipar,long data,int type)423 static int yybindpar(yystmt_t* yystmt, int ipar, long data, int type)
424 {
425 int i;
426
427 ipar --;
428
429 if( ! yystmt->ppar )
430 {
431 yystmt->ppar = (yypar_t*)MEM_ALLOC(
432 sizeof(yypar_t)*MAX_PARAM_NUMBER);
433
434 if( ! yystmt->ppar )
435 {
436 yystmt->errcode = -1;
437 return -1;
438 }
439
440 for(i=0; i<MAX_PARAM_NUMBER; i++)
441 (yystmt->ppar)[i].type = -1; /* unbind */
442 }
443
444 yyunbindpar( yystmt, ipar + 1);
445
446 (yystmt->ppar)[ipar].type = type;
447
448 switch(type)
449 {
450 case en_nt_null:
451 return 0;
452
453 case en_nt_qstr:
454 (yystmt->ppar)[ipar].value.location = (char*)data;
455 break;
456
457 case en_nt_num:
458 (yystmt->ppar)[ipar].value.number = (long)data;
459 break;
460
461 case en_nt_date:
462 (yystmt->ppar)[ipar].value.date = *((date_t*)data);
463 break;
464
465 default:
466 abort();
467 break;
468 }
469
470 return 0;
471 }
472
nnsql_putnull(void * hstmt,int ipar)473 int nnsql_putnull(void* hstmt, int ipar )
474 {
475 return yybindpar((yystmt_t*)hstmt, ipar, 0, en_nt_null);
476 }
477
nnsql_putstr(void * hstmt,int ipar,char * str)478 int nnsql_putstr(void* hstmt, int ipar, char* str)
479 {
480 return yybindpar((yystmt_t*)hstmt, ipar, (long)str, en_nt_qstr);
481 }
482
nnsql_putnum(void * hstmt,int ipar,long num)483 int nnsql_putnum(void* hstmt, int ipar, long num)
484 {
485 return yybindpar((yystmt_t*)hstmt, ipar, num, en_nt_num);
486 }
487
nnsql_putdate(void * hstmt,int ipar,date_t * date)488 int nnsql_putdate(void* hstmt, int ipar, date_t* date)
489 {
490 return yybindpar((yystmt_t*)hstmt, ipar, (long)(date), en_nt_date);
491 }
492
nnsql_max_param()493 int nnsql_max_param()
494 {
495 return MAX_PARAM_NUMBER;
496 }
497
nnsql_max_column()498 int nnsql_max_column()
499 {
500 return MAX_COLUMN_NUMBER;
501 }
502
access_mode_chk(yystmt_t * pstmt)503 static int access_mode_chk( yystmt_t* pstmt )
504 {
505 int mode;
506
507 pstmt->errcode = 0;
508 mode = nntp_getaccmode(pstmt->hcndes);
509
510 switch( pstmt->type )
511 {
512 case en_stmt_insert:
513 if( mode < ACCESS_MODE_INSERT )
514 pstmt->errcode = NO_INSERT_PRIVILEGE;
515 break;
516
517 case en_stmt_srch_delete:
518 if( nnsql_strlike( pstmt->table, "%.test", 0, 0) )
519 {
520 if( mode < ACCESS_MODE_DELETE_TEST )
521 pstmt->errcode = NO_DELETE_PRIVILEGE;
522 }
523 else
524 {
525 if( mode < ACCESS_MODE_DELETE_ANY )
526 pstmt->errcode = NO_DELETE_ANY_PRIVILEGE;
527 }
528 if( nnsql_opentable(pstmt, 0) )
529 return -1;
530 break;
531
532 case en_stmt_select:
533 if( nnsql_opentable(pstmt, 0) )
534 return -1;
535 return 0;
536
537 default:
538 pstmt->errcode = -1;
539 break;
540 }
541
542 if( ! pstmt->errcode && ! nntp_postok( pstmt->hcndes ) )
543 pstmt->errcode = NO_POST_PRIVILEGE;
544
545 if( pstmt->errcode )
546 {
547 nnsql_resetyystmt(pstmt);
548 return -1;
549 }
550
551 return 0;
552 }
553
nnsql_prepare(void * hstmt,char * expr,int len)554 int nnsql_prepare(void* hstmt, char* expr, int len)
555 {
556 yyenv_t yyenv;
557 yystmt_t* pstmt = hstmt;
558 int r;
559
560 if( ! hstmt || ! expr || len < 0 )
561 return -1;
562
563 nnsql_resetyystmt(hstmt);
564
565 pstmt->errcode = -1;
566
567 pstmt->sqlexpr = MEM_ALLOC(len + 1);
568
569 if( ! pstmt->sqlexpr )
570 return -1;
571
572 pstmt->texts_buf = MEM_ALLOC( len + 1 );
573
574 if( ! pstmt->texts_buf )
575 {
576 MEM_FREE( pstmt->sqlexpr );
577 pstmt->sqlexpr = 0;
578
579 return -1;
580 }
581
582 STRNCPY(pstmt->sqlexpr, expr, len);
583 (pstmt->sqlexpr)[len] = 0;
584
585 nnsql_yyinit(&yyenv, pstmt);
586
587 if( nnsql_yyparse(&yyenv)
588 || access_mode_chk( pstmt ) )
589 {
590 nnsql_resetyystmt(pstmt);
591 return -1;
592 }
593
594 return 0;
595 }
596
nnsql_column_descid(void * hstmt,int icol)597 int nnsql_column_descid(void* hstmt, int icol)
598 {
599 if( icol < 0 || icol > MAX_COLUMN_NUMBER )
600 return -1;
601
602 return (((yystmt_t*)hstmt)->pcol)[icol].iattr;
603 }
604
do_insert(void * hstmt)605 static int do_insert(void* hstmt)
606 {
607 yystmt_t* pstmt = hstmt;
608 char *body, *head, *value;
609 node_t* node;
610 int i, attridx;
611 yypar_t* par;
612 int subj_set = 0, from_set = 0;
613
614 pstmt->count = 0;
615
616 if( nntp_start_post( pstmt->hcndes)
617 || nntp_send_head( pstmt->hcndes,
618 "X-Newsreader", "NetNews SQL Agent v0.5")
619 || nntp_send_head( pstmt->hcndes,
620 "Newsgroups", pstmt->table ) )
621 return -1;
622
623 for(i=0; ;i++)
624 {
625 head = (pstmt->ins_heads)[i];
626
627 if( ! head )
628 break;
629
630 if( ! *head )
631 continue;
632
633 attridx = nnsql_getcolidxbyname( head );
634
635 switch( attridx )
636 {
637 case en_article_num:
638 case en_x_newsreader:
639 case en_newsgroups:
640 case en_xref:
641 case en_host:
642 case en_date:
643 case en_path:
644 case en_lines:
645 case en_msgid: /* better to let srv set id */
646 continue;
647
648 case en_subject:
649 subj_set = 1;
650 break;
651
652 case en_from:
653 from_set = 1;
654 break;
655
656 case -1: /* an extended header */
657 break;
658
659 default: /* any normal header */
660 head = nnsql_getcolnamebyidx(attridx);
661 /* use stand representation */
662 break;
663 }
664
665 node = pstmt->ins_values + i;
666
667 switch(node->type)
668 {
669 case en_nt_qstr:
670 value = node->value.qstr;
671 break;
672
673 case en_nt_null:
674 continue;
675
676 case en_nt_param:
677 par = pstmt->ppar + (node->value).ipar - 1;
678
679 if(par->type != en_nt_qstr )
680 continue;
681
682 value = (par->value).location;
683 break;
684
685 default:
686 continue;
687 }
688
689 if( attridx == en_body )
690 {
691 body = value;
692 continue;
693 }
694
695 nntp_send_head(pstmt->hcndes, head, value);
696 }
697
698 if( !subj_set )
699 nntp_send_head(pstmt->hcndes, "Subject", "(none)");
700
701 if( !from_set )
702 nntp_send_head(pstmt->hcndes, "From", "(none)");
703
704 if( nntp_end_head (pstmt->hcndes)
705 || nntp_send_body(pstmt->hcndes, body)
706 || nntp_end_post (pstmt->hcndes) )
707 return -1;
708
709 pstmt->count = 1;
710
711 return 0;
712 }
713
do_srch_delete(void * hstmt)714 int do_srch_delete(void* hstmt)
715 {
716 int r, i, rcnt;
717 yystmt_t* pstmt = hstmt;
718 yyattr_t* pattr = pstmt->pattr;
719
720 pstmt->count = 0;
721
722 for(;;)
723 {
724 r = yyfetch(hstmt, 1);
725
726 switch(r)
727 {
728 case 100:
729 pstmt->type = en_stmt_alloc;
730 return 0;
731
732 case -1:
733 pstmt->type = en_stmt_alloc;
734 return -1;
735
736 case 0:
737 r = nnsql_srchtree_evl(hstmt);
738
739 switch(r)
740 {
741 case -1:
742 pstmt->type = en_stmt_alloc;
743 return -1;
744
745 case 1:
746 for(rcnt=0; r && rcnt<6; rcnt++)
747 /* retry 6 times */
748 {
749 if(rcnt && pstmt->count )
750 sleep(1 + rcnt);
751 /* give server time to
752 * finish previous DELETE
753 */
754
755 r = nntp_cancel(
756 pstmt->hcndes,
757 pstmt->table,
758 pattr[en_sender].value.location,
759 pattr[en_from].value.location,
760 pattr[en_msgid].value.location);
761 }
762
763 if( r )
764 return -1;
765
766 pstmt->count++;
767 continue;
768
769 case 0:
770 continue;
771
772 default:
773 abort();
774 break;
775 }
776 break;
777
778 default:
779 abort();
780 break;
781 }
782
783 break;
784 }
785
786 abort();
787
788 return -1;
789 }
790
nnsql_execute(void * hstmt)791 int nnsql_execute(void* hstmt)
792 {
793 yystmt_t* pstmt = hstmt;
794 yypar_t* par;
795 int i;
796
797 par = pstmt->ppar;
798
799 if( !par && pstmt->npar )
800 return 99;
801
802 for(i=0;i<pstmt->npar;i++)
803 {
804 par = pstmt->ppar + i;
805
806 if(par->type == -1)
807 return 99;
808 }
809
810 switch(pstmt->type)
811 {
812 case en_stmt_insert:
813 return do_insert(hstmt);
814
815 case en_stmt_srch_delete:
816 case en_stmt_select:
817 if( nnsql_srchtree_tchk(hstmt)
818 || nnsql_opentable(hstmt, 0) )
819 break;
820
821 if( pstmt->type == en_stmt_srch_delete )
822 return do_srch_delete(hstmt);
823
824 return 0;
825
826 default:
827 break;
828 }
829
830 return -1;
831 }
832
nnsql_isnullablecol(void * hstmt,int icol)833 int nnsql_isnullablecol( void* hstmt, int icol )
834 {
835 switch( (((yystmt_t*)hstmt)->pcol + icol)->iattr )
836 {
837 case en_subject:
838 case en_from:
839 case en_body:
840 return 0;
841
842 default:
843 break;
844 }
845
846 return 1;
847 }
848
nnsql_isnumcol(void * hstmt,int icol)849 int nnsql_isnumcol(void* hstmt, int icol )
850 {
851 switch( (((yystmt_t*)hstmt)->pcol + icol)->iattr )
852 {
853 case en_lines:
854 case en_article_num:
855 case en_sql_count:
856 case en_sql_num:
857 return 1;
858
859 default:
860 break;
861 }
862
863 return 0;
864 }
865
nnsql_isdatecol(void * hstmt,int icol)866 int nnsql_isdatecol(void* hstmt, int icol)
867 {
868 switch( (((yystmt_t*)hstmt)->pcol + icol)->iattr )
869 {
870 case en_date:
871 case en_sql_date:
872 return 1;
873
874 default:
875 break;
876 }
877
878 return 0;
879 }
880
nnsql_getnum(void * hstmt,int icol)881 long nnsql_getnum(void* hstmt, int icol )
882 {
883 yystmt_t* pstmt = hstmt;
884 yycol_t* pcol;
885
886 pcol = ((yystmt_t*)hstmt)->pcol + icol;
887
888 switch( pcol->iattr )
889 {
890 case en_lines:
891 case en_article_num:
892 return ((pstmt->pattr + pcol->iattr)->value).number;
893
894 case en_sql_num:
895 return (pcol->value).num;
896
897 case en_sql_count:
898 return (pstmt->count);
899
900 default:
901 break;
902 }
903
904 return 0;
905 }
906
nnsql_isstrcol(void * hstmt,int icol)907 int nnsql_isstrcol(void* hstmt, int icol )
908 {
909 return ! nnsql_isnumcol(hstmt, icol) && ! nnsql_isdatecol(hstmt, icol);
910 }
911
nnsql_getstr(void * hstmt,int icol)912 char* nnsql_getstr(void* hstmt, int icol )
913 {
914 yystmt_t* pstmt = hstmt;
915 yycol_t* pcol;
916
917 pcol = ((yystmt_t*)hstmt)->pcol + icol;
918
919 switch( pcol->iattr )
920 {
921 case en_lines:
922 case en_article_num:
923 case en_sql_count:
924 case en_sql_num:
925 return 0;
926
927 case en_sql_qstr:
928 return (pcol->value).qstr;
929
930 default:
931 break;
932 }
933
934 return ((pstmt->pattr + pcol->iattr)->value).location;
935 }
936
nnsql_getdate(void * hstmt,int icol)937 date_t* nnsql_getdate(void* hstmt, int icol )
938 {
939 yystmt_t* pstmt = hstmt;
940 yycol_t* pcol;
941
942 pcol = ((yystmt_t*)hstmt)->pcol + icol;
943
944 switch( pcol->iattr )
945 {
946 case en_date:
947 return &(((pstmt->pattr + pcol->iattr)->value).date);
948
949 case en_sql_date:
950 return &((pcol->value).date);
951
952 default:
953 break;
954 }
955
956 return 0;
957 }
958
959
nnsql_iscountcol(void * hstmt,int icol)960 int nnsql_iscountcol(void* hstmt, int icol )
961 {
962 return ( (((yystmt_t*)hstmt)->pcol + icol)->iattr == en_sql_count );
963 }
964
nnsql_isnullcol(void * hstmt,int icol)965 int nnsql_isnullcol(void* hstmt, int icol )
966 {
967 yystmt_t* pstmt = hstmt;
968 yycol_t* pcol;
969 long artnum;
970 date_t* date;
971
972 artnum = (pstmt->pattr->value).number;
973
974 pcol = ((yystmt_t*)hstmt)->pcol + icol;
975
976 switch( pcol->iattr )
977 {
978 case en_sql_count:
979 return !!artnum;
980
981 case en_sql_num:
982 case en_sql_qstr:
983 case en_sql_date:
984 case en_lines:
985 case en_article_num:
986 return !artnum;
987
988 case en_date:
989 date = nnsql_getdate(hstmt, icol);
990 return !artnum || !date || !date->day;
991
992 default:
993 break;
994 }
995
996 return !artnum || !nnsql_getstr(hstmt, icol);
997 }
998
nnsql_getcolnum(void * hstmt)999 int nnsql_getcolnum(void* hstmt)
1000 {
1001 return ((yystmt_t*)hstmt)->ncol;
1002 }
1003
nnsql_getparnum(void * hstmt)1004 int nnsql_getparnum(void* hstmt)
1005 {
1006 return ((yystmt_t*)hstmt)->npar;
1007 }
1008
nnsql_getrowcount(void * hstmt)1009 int nnsql_getrowcount(void* hstmt)
1010 {
1011 return ((yystmt_t*)hstmt)->count;
1012 }
1013