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