
	kraehe@bakunin.north.de			Wed May 22 19:37:14  1996

	ftp://ftp.uni-bremen.de/pub/unix/database/Minerva/features-msql-1.0.14

	Hy folks, this is my feature adding patch to msql 1.0.14 
	-----------------------------------------------------------------

	This patch includes the following features :

	- Usage of double quotes for strings. I know this is not ISO
	  but a lot of other databases also allow double quotes and
	  some of my programs use double qoutes.
	- Speedup of regular expression.
	- Simple expressions in update.
	- auto primary key insert.
	- Some bug fixes.

	as an example asume that a relation stock contains 

		nr		int primary key,
		isbn		char(30),
		autor		char(30),
		title		char(30),
		publisher	char(30),
		quant		int

	so you can now query :

		select * from stock where autor like "%Sullivan%";
	or	select * from stock where autor like '%Sullivan%';
	or	update stock set quant = quant + 5 where isbn = 1857270053;
	or	insert into stock (nr,isbn,autor,title,publisher,quant)
		values (NULL, "1857270312", "Hauer",
		        "The Good, The Bad and The Gorgeous",
		        "SCARLET PRESS",
		        1);

	as default all features are patched in.

	In msql/msql_priv.h you can comment out if you dont like to
	include all features. Be aware that its not posible to #ifdef
	in a yacc grammar. So if you dont need the update patch, you
	have to move the original msql_yacc.y~ to msql_yacc.c.

	Copyright notice :
	------------------

	Bambi dont like my patches, which exists since 1.0.5, and
	didnt applied them to the official msql tree (I have asked
	him often) He even deleted my patches on ftp.bond.edu.au.

	So I deceided not to upload them on ftp.bond.edu.au any more,
	but to use my site ftp.uni-bremen.de. I also decided to use
	GPL for this patch, as all things I write are under GPL !

	So you are not allowed to distribute a binary of msql with
	my patch if you dont distribute the source also ! 

	Ok I know this locks the door for Bambi for applying my
	patches ! But I've asked him since 1.0.5 and his answer
	was "NO" all the time.


*** ./msql/msql_priv.h~	Mon Feb  5 15:14:38 1996
--- ./msql/msql_priv.h	Wed May 22 17:43:08 1996
***************
*** 15,20 ****
--- 15,28 ----
  ** ID = "msql_priv.h,v 1.3 1994/08/19 08:03:14 bambi Exp"
  */
  
+ #define FEATURE_DQ YES		/* double quotes for strings */
+ #define FEATURE_UP YES		/* calculations in update */
+ /* move original msql_yacc.c~ to msql_yacc.c if not using FEATURE_UP
+    yacc is called before cpp */
+ #define FEATURE_AK YES		/* auto primary key in insert */
+ #define FEATURE_RE YES		/* regexp speedup */
+ #define FEATURE_BUG YES		/* some bug fixes */
+ 
  #include "version.h"
  
  #ifdef NEW_DB
***************
*** 64,70 ****
--- 72,85 ----
  		double	realVal;
  		ident_t	*identVal;
  	} val;
+ #ifndef FEATURE_UP
  	int	type,
+ #else
+ 	char	table[NAME_LEN],
+ 		name[NAME_LEN];
+ 	int	op,offs,ftype,
+ 		type,
+ #endif /* FEATURE */
  		nullVal,
  		dataLen;
  } val_t;
***************
*** 91,97 ****
  	struct	field_ps *next;
  } field_t;
  
- 
  /* 
  ** Where clause list element 
  */
--- 106,111 ----
***************
*** 246,251 ****
--- 260,272 ----
  #define GE_OP		6
  #define LIKE_OP		7
  #define NOT_LIKE_OP	8
+ #ifdef FEATURE_UP
+ 
+ #define PLU_OP		9
+ #define MIN_OP		10
+ #define MUL_OP		11
+ #define DIV_OP		12
+ #endif /* FEATURE */
  
  #define	NO_BOOL		0
  #define	AND_BOOL	1
*** ./msql/msqldb.c~	Mon May  6 10:01:13 1996
--- ./msql/msqldb.c	Wed May 22 19:35:47 1996
***************
*** 2239,2244 ****
--- 2239,2250 ----
  		{
  			(void)strcpy(curField->table,table);
  		}
+ #ifdef FEATURE_UP
+ 		if (curField->value && *(curField->value->name) && !*(curField->value->table))
+ 		{
+ 			(void)strcpy(curField->value->table,table);
+ 		}
+ #endif /* FEATURE */
  		curField=curField->next;
  	}
  	msqlTrace(TRACE_OUT,"qualifyField()");
***************
*** 2545,2550 ****
--- 2551,2632 ----
  	msqlTrace(TRACE_OUT,"setupFields()");
  	return(0);
  }
+ #ifdef FEATURE_UP
+ /****************************************************************************
+ ** 	_setupVal
+ **
+ **	Purpose	: Determine the byte offset into a row of the desired values
+ **	Args	: Empty field list (field location) array,
+ **		  List of desired fields
+ **	Returns	: -1 on error
+ **	Notes	: The field list array holds the byte offsets for the
+ **		  fields.  ie. array element 0 will hold the byte offset
+ **		  of the first desired field etc.
+ */
+ 
+ static int setupVal(cacheEntry, fields)
+ 	cache_t	*cacheEntry;
+ 	field_t	*fields;
+ {
+ 	REG 	field_t	*curField,
+ 			*fieldDef;
+ 	int	curOffset;
+ 
+ 	msqlTrace(TRACE_IN,"setupVal()");
+ 
+ 	curField = fields;
+ 	
+ 	while(curField)
+ 	{
+ 	    if (curField->value && *(curField->value->name))
+ 	    {
+ 		    fieldDef = cacheEntry->def;
+ 		    curOffset = 0;
+ 		    while(fieldDef)
+ 		    {
+ 			if(strcmp(curField->value->name,fieldDef->name) == 0 &&
+ 			   strcmp(curField->value->table,fieldDef->table) == 0)
+ 			{
+ 				curField->value->ftype= fieldDef->type;
+ 				curField->value->offs = curOffset;
+ 				if (curField->type != curField->value->ftype)
+ 				{
+ 					sprintf(errMsg, TYPE_ERROR, curField->name);
+ 					msqlDebug(MOD_ERR,TYPE_ERROR, curField->name);
+ 					return(-1);
+ 				}
+ 				break;
+ 			}
+ 			curOffset += fieldDef->length+1; /* +1 for null indicator */
+ 			fieldDef = fieldDef->next;
+ 		    }
+ 		    if(!fieldDef)  /* Bad entry */
+ 		    {
+ 			if (curField->value->table)
+ 			{
+ 			    sprintf(errMsg,"Unknown field \"%s.%s\"",
+ 					curField->value->table,curField->value->name);
+ 			    msqlDebug(MOD_ERR,"Unknown field \"%s.%s\"\n",
+ 					curField->value->table,curField->value->name);
+ 			    msqlTrace(TRACE_OUT,"setupVal()");
+ 			    return(-1);
+ 			}
+ 			else
+ 			{
+ 			    sprintf(errMsg,"Unknown field \"%s\"",curField->value->name);
+ 			    msqlDebug(MOD_ERR,"Unknown field \"%s\"\n",curField->value->name);
+ 			    msqlTrace(TRACE_OUT,"setupVal()");
+ 			    return(-1);
+ 			}
+ 		    }
+ 	    }
+ 	    
+ 	    curField = curField->next;
+ 	}
+ 	msqlTrace(TRACE_OUT,"setupVal()");
+ 	return(0);
+ }
+ #endif /* FEATURE */
  
  
  
***************
*** 2912,2949 ****
--- 2994,3115 ----
  	int	*offset;
  	field_t	*curField;
  	char	*cp;
+ #ifdef FEATURE_UP
+ 	int	iVal,iFVal;
+ 	double	dVal,dFVal;
+ 	char	*cVal;
+ #endif /* FEATURE */
  
  	msqlTrace(TRACE_IN,"updateValues()");
  	curField = fields;
  	offset = flist;
  	while(curField)
  	{
+ #ifndef FEATURE_UP
  		cp = row + *offset;
+ #endif /* FEATURE */
  		if (!curField->value->nullVal)
                  {
+ #ifdef FEATURE_UP
+ 			switch(curField->type)
+ 			{
+ 				case INT_TYPE:
+ 				 	iVal = curField->value->val.intVal;
+ 					break;
+ 		
+ 				case CHAR_TYPE:
+ 					cVal = curField->value->val.charVal;
+ 					break;
+ 
+ 				case REAL_TYPE:
+ 					dVal = curField->value->val.realVal;
+ 					break;
+ 			}
+ 			if (curField->value->op && curField->value->offs)
+ 			{
+                             cp = row + curField->value->offs +1;
+                             if (curField->type == INT_TYPE)
+ 			    {
+ 			    	memcpy(&iFVal,cp,sizeof(int));
+                             	switch(curField->value->op)
+                             	{
+                             	    case PLU_OP:
+                             	    	iVal += iFVal ;
+                             	    	break;
+                             	    case MIN_OP:
+                             	    	iVal = iFVal -iVal;
+                             	    	break;
+                             	    case MUL_OP:
+                             	    	iVal = iFVal *iVal;
+                             	    	break;
+                             	    case DIV_OP:
+                             	    	if (iVal)
+                             	    		iVal = iFVal /iVal;
+                             	    	break;
+                             	}
+                             }
+                             if (curField->type == REAL_TYPE)
+                             {	
+ 			    	memcpy(&dFVal,cp,sizeof(int));
+                             	switch(curField->value->op)
+                             	{
+                             	    case PLU_OP:
+                             	    	dVal += dFVal ;
+                             	    	break;
+                             	    case MIN_OP:
+                             	    	dVal = dFVal -dVal;
+                             	    	break;
+                             	    case MUL_OP:
+                             	    	dVal = dFVal +dVal;
+                             	    	break;
+                             	    case DIV_OP:
+                             	    	if (dVal != 0.0)
+                             	    		dVal = dFVal / dVal;
+                             	    	break;
+                             	}
+                             }
+                         }
+                         cp = row + *offset;
+ #endif /* FEATURE */
                          *cp = '\001';
                          cp++;
  			switch(curField->type)
  			{
  				case INT_TYPE:
  #ifndef _CRAY
+ #ifndef FEATURE_UP
  					bcopy4(&(curField->value->val.intVal),
  						cp);
  #else
+  					bcopy(&iVal,cp, sizeof(int));
+ #endif /* FEATURE */
+ #else
+ #ifndef FEATURE_UP
  				 	packInt32(curField->value->val.intVal, 
  						cp);
+ #else
+  				 	packInt32(iVal, cp);
+ #endif /* FEATURE */
  #endif
  					break;
  		
  				case CHAR_TYPE:
  					(void)bzero(cp, curField->length);
+ #ifndef FEATURE_UP
  					strncpy(cp, curField->value->val.charVal,
  						curField->length);
+ #else
+  					strncpy(cp, cVal, curField->length);
+ #endif /* FEATURE */
  					break;
  
  				case REAL_TYPE:
+ #ifndef FEATURE_UP
  					bcopy8(&(curField->value->val.realVal),
  						cp);
+ #else
+  					bcopy(&dVal,cp, sizeof(double));
+ #endif /* FEATURE */
  					break;
  			}
  		}
***************
*** 2961,2967 ****
  
  
  
- 
  /****************************************************************************
  ** 	_translateValues
  **
--- 3127,3132 ----
***************
*** 3099,3116 ****
  	msqlTrace(TRACE_OUT,"extractValues()");
  }
  
- 
- 
  static char	regErrFlag;
  
  void regerror()
  {
  	regErrFlag++;
  }
  
- 
- 
- 
  static int regexpTest(str,re,maxLen)
  	char	*str,
  		*re;
--- 3264,3281 ----
  	msqlTrace(TRACE_OUT,"extractValues()");
  }
  
  static char	regErrFlag;
  
+ #ifdef FEATURE_RE
+ static char    *regspeedbuff = 0;
+ static regexp  *regspeed = 0;
+ #endif
+ 
  void regerror()
  {
  	regErrFlag++;
  }
  
  static int regexpTest(str,re,maxLen)
  	char	*str,
  		*re;
***************
*** 3125,3130 ****
--- 3290,3302 ----
  	regexp	*reg;
  	int	res;
  
+ #ifdef FEATURE_RE
+ 	if (!regspeed || !regspeedbuff || strcmp(re,regspeedbuff)) {
+ 		if (regspeed) { safeFree(regspeed); }
+ 		if (regspeedbuff) { safeFree(regspeedbuff); }
+ 		regspeedbuff=(char *)strdup(re);
+ #endif /* FEATURE_RE */
+ 
  	/*
  	** Map an SQL regexp into a UNIX regexp
  	*/
***************
*** 3171,3176 ****
--- 3343,3353 ----
  	}
  	*cp2 = '$';
  
+ #ifdef FEATURE_RE
+ 		regspeed = reg = regcomp(regbuf);
+ 		}
+ #endif
+ 
  	/*
  	** Do the regexp thang.  We do an ugly hack here : The data of
  	** a field may be exactly the same length as the field itself.
***************
*** 3192,3200 ****
--- 3369,3382 ----
  		strncpy(tmpBuf,str,maxLen);
  		strPtr = tmpBuf;
  	}
+ 
+ #ifdef FEATURE_RE
+ 	res = regexec(regspeed,strPtr);
+ #else
  	reg = regcomp(regbuf);
  	res = regexec(reg,strPtr);
  	safeFree(reg);
+ #endif
  	if (tmpBuf)
  		free(tmpBuf);
  	if (regErrFlag)
***************
*** 4264,4269 ****
--- 4446,4463 ----
  
  	if (key)
  	{
+ #ifdef FEATURE_AK
+ 			/* check for autokey generation */
+ 		if (key->type == INT_TYPE && key->value->nullVal) {
+ 		   int freeKey = cacheEntry->numRows;
+ 		   key->value->nullVal = 0;
+ 		   key->value->type = INT_TYPE;
+ 		   do {
+ 			freeKey++;
+ 			key->value->val.intVal = freeKey;
+ 		   } while (readKey(cacheEntry,key) != NO_POS);
+ 		}
+ #endif /* FEATURE */
  		if (readKey(cacheEntry,key) != NO_POS)
  		{
  			sprintf(errMsg,KEY_UNIQ_ERROR, key->name);
***************
*** 4342,4347 ****
--- 4536,4548 ----
  	qualifyConds(table,conds);
  	(void)bzero(flist,MAX_FIELDS * sizeof(int));
  	if (setupFields(cacheEntry,flist,fields,&keyField) < 0)
+ #ifdef FEATURE_UP
+ 	{
+ 		msqlTrace(TRACE_OUT,"msqlUpdate()");
+ 		return(-1);
+ 	}
+ 	if (setupVal(cacheEntry,fields) < 0)
+ #endif /* FEATURE */
  	{
  		msqlTrace(TRACE_OUT,"msqlUpdate()");
  		return(-1);
*** ./msql/msql_yacc.y~	Sun Apr 21 08:38:00 1996
--- ./msql/msql_yacc.y	Wed May 22 17:40:33 1996
***************
*** 95,100 ****
--- 95,107 ----
  
  %token  LIMIT
  
+ /* ifdef FEATURE_UP */
+ %token  OPPLU
+ %token  OPMIN
+ %token  OPMUL
+ %token  OPDIV
+ /* endif FEATURE */
+ 
  %%
  
  /*
***************
*** 219,225 ****
--- 226,236 ----
  item_list
  	: item_list ',' field
  	| field
+ /* ifndef FEATURE_UP
  	| '*'
+    else */
+ 	| OPMUL
+ /* endif FEATURE */
  		{
  			ident_t	*tmp;
  
***************
*** 382,392 ****
--- 393,411 ----
  values
  	: values ','  literal
  		{ 
+ /* ifndef FEATURE_UP
  			msqlAddFieldValue($3);
+    else */
+ 			msqlAddFieldValue($3,0,0);
+ /* endif FEATURE */
  		 }
  	|  literal
  		{ 
+ /* ifndef FEATURE_UP
  			msqlAddFieldValue($1); 
+    else */
+ 			msqlAddFieldValue($1,0,0); 
+ /* endif FEATURE */
  		}
  
  
***************
*** 403,408 ****
--- 422,428 ----
  			myFree($2);
  		}
  
+ /* ifndef FEATURE_UP
  update_list
  	: update_list ',' qual_ident EQ literal
  		{ msqlAddField($3,0,0,0,0);
***************
*** 410,416 ****
--- 430,456 ----
  	| qual_ident EQ literal
  		{ msqlAddField($1,0,0,0,0);
  		  msqlAddFieldValue($3); }
+    else */
+ 
+ update_list
+ 	: update_list ',' update_set
+ 	| update_set
  
+ update_set : qual_ident EQ literal
+ 		{ msqlAddField($1,0,0,0,0);
+ 		  msqlAddFieldValue($3,0,0); 
+ 		  }
+ 	| qual_ident EQ qual_ident numop literal
+ 		{ msqlAddField($1,0,0,0,0);
+ 		  msqlAddFieldValue($5,$3,$4);
+ 		  }
+ 
+ numop : OPPLU { $$ = (char *)PLU_OP; }
+ 	| OPMIN { $$ = (char *)MIN_OP; }
+ 	| OPMUL { $$ = (char *)MUL_OP; }
+ 	| OPDIV { $$ = (char *)DIV_OP; }
+ 
+ /* endif FEATURE */
  
  /*
  ** Delete : conditionally delete table entries (or all entries)
***************
*** 444,449 ****
--- 484,521 ----
  		{
  			$$ = (char *)msqlCreateValue($1,REAL_TYPE,0);
  			(void)myFree($1);
+ 		}
+ /* ifdef FEATURE_UP */
+ 	| OPPLU NUM
+ 		{
+ 			$$ = (char *)msqlCreateValue($2,INT_TYPE,0);
+ 			(void)myFree($2);
+ 		}
+ 	| OPPLU REAL_NUM
+ 		{
+ 			$$ = (char *)msqlCreateValue($2,REAL_TYPE,0);
+ 			(void)myFree($2);
+ 		}
+ 	| OPMIN NUM
+ 		{	char *p;
+ 
+ 			p=(char*)malloc(strlen($2)+2);
+ 			*p='-'; strcpy(p+1,$2);
+ 			$$ = (char *)msqlCreateValue(p,INT_TYPE,0);
+ 			(void)myFree($2);
+ 
+ 			free(p);
+ 		}
+ 	| OPMIN REAL_NUM
+ 		{	char *p;
+ 
+ 			p=(char*)malloc(strlen($2)+2);
+ 			*p='-'; strcpy(p+1,$2);
+ 			$$ = (char *)msqlCreateValue(p,REAL_TYPE,0);
+ 			(void)myFree($2);
+ 
+ 			free(p);
+ /* endif FEATURE */
  		}
  	| NULLSYM
  		{
*** ./msql/msql_proc.c~	Tue Mar  5 15:58:40 1996
--- ./msql/msql_proc.c	Wed May 22 17:49:31 1996
***************
*** 246,251 ****
--- 246,255 ----
  
  	msqlTrace(TRACE_IN,"msqlCreateValue()");
  	new = (val_t *)malloc(sizeof(val_t));
+ #ifdef FEATURE_BUG
+ 	*(new->table) = *(new->name) = 0;
+ 	new->offs=0;
+ #endif /* FEATURE */
  	new->type = type;
  	new->dataLen = tokLen;
  	switch(type)
***************
*** 492,499 ****
--- 496,510 ----
  }
  
  
+ #ifndef FEATURE_UP
  msqlAddFieldValue(value)
  	val_t	*value;
+ #else
+ msqlAddFieldValue(value,ident,operator)
+ 	val_t	*value;
+  	ident_t *ident;
+  	int operator;
+ #endif /* FEATURE */
  {
  	register field_t	*fieldVal;
  	u_char	*buf;
***************
*** 508,513 ****
--- 519,542 ----
  		fieldVal = lastField->next;
  		lastField = lastField->next;
  	}
+ #ifdef FEATURE_UP
+ 	if (ident && operator)
+ 	{
+ 		value->op=operator;
+ 
+ 		if (*(ident->seg1))
+ 		{
+ 			(void)strncpy(value->table,ident->seg1,NAME_LEN - 1);
+ 			(void)strncpy(value->name ,ident->seg2,NAME_LEN - 1);
+ 		}
+ 		else
+ 		{
+ 			(void)memset(value->table,0,NAME_LEN);
+ 			(void)strncpy(value->name ,ident->seg2,NAME_LEN - 1);
+ 		}
+ 		free(ident);
+ 	}
+ #endif /* FEATURE */
  	if (fieldVal)
  	{
  		if (fieldVal->type == CHAR_TYPE)
***************
*** 549,562 ****
--- 578,599 ----
  
  	msqlTrace(TRACE_IN,"msqlAddCond()");
  
+ #ifndef FEATURE_BUG
  	if (*(ident->seg2))
+ #else
+ 	if (*(ident->seg1))
+ #endif /* FEATURE */
  	{
  		name = ident->seg2;
  		table = ident->seg1;
  	}
  	else
  	{
+ #ifndef FEATURE_BUG
  		name = ident->seg1;
+ #else
+ 		name = ident->seg2;
+ #endif /* FEATURE */
  		table = NULL;
  	}
  
*** ./msql/msql_lex.c~	Sun Apr 21 08:38:00 1996
--- ./msql/msql_lex.c	Wed May 22 15:41:01 1996
***************
*** 296,301 ****
--- 296,305 ----
  }
  
  
+ #ifdef FEATURE_DQ
+ u_char readTextLiteralDelimiter;
+ #endif /* FEATURE */
+ 
  u_char *readTextLiteral(tok)
  	u_char	*tok;
  {
***************
*** 318,324 ****
--- 322,334 ----
  				break;
  	
  			case '\'':
+ #ifndef FEATURE_DQ
  				bail=1;
+ #else
+ 			case '"':
+ 				if (readTextLiteralDelimiter == c)
+ 					bail=1;
+ #endif /* FEATURE */
  				break;
  		}
  	}
***************
*** 365,372 ****
--- 375,388 ----
  						yylineno++;
  					c = yySkip();
  				}
+ #ifndef FEATURE_DQ
  				if (c == '\'')
  				{
+ #else
+ 				if ((c == '\'') || (c == '"'))
+ 				{
+ 					readTextLiteralDelimiter=c;
+ #endif /* FEATURE */
  					state = 12;
  					break;
  				}
***************
*** 392,402 ****
--- 408,430 ----
  					else
  						yyUnget();
  				}
+ #ifndef FEATURE_UP
  				if (c == '-' || c == '+')
  				{
  					state = 9;
  					break;
  				}
+ #else
+ 				if ((c == '+') || (c == '-')
+ 				 || (c == '*') || (c == '/')) {
+ 					yytext = tokenDup(tokStart,yytoklen);
+ 					yylval = (YYSTYPE) yytext;
+ 					if (c == '+') yyReturn(OPPLU);
+ 					if (c == '-') yyReturn(OPMIN);
+ 					if (c == '*') yyReturn(OPMUL);
+ 					if (c == '/') yyReturn(OPDIV);
+ 					}
+ #endif /* FEATURE */
  				if (iscompop(c))
  				{
  					state = 10;
***************
*** 563,569 ****
  				}
  				state = 999;
  				break;
- 
  	
  			/* State 12: Incomplete text string */
  			CASE(12)
--- 591,596 ----
***************
*** 577,589 ****
  				state = 999;
  				break;
  
- 
- 
  			/* State 13: Complete text string */
  			CASE(13)
  				yyReturn(token(TEXT));
  				break;
- 
  
  			/* State 14: Comment */
  			CASE(14)
--- 604,613 ----
