Add DATETIME type.

This commit is contained in:
dfs
2007-06-28 03:04:44 +00:00
parent 614ab08099
commit 9501498a7e
3 changed files with 104 additions and 16 deletions

View File

@@ -11,7 +11,7 @@
/***************************************************************/ /***************************************************************/
#include "config.h" #include "config.h"
static char const RCSID[] = "$Id: expr.c,v 1.10 2005-09-30 03:29:32 dfs Exp $"; static char const RCSID[] = "$Id: expr.c,v 1.11 2007-06-28 03:04:44 dfs Exp $";
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@@ -44,7 +44,7 @@ static int Multiply(void), Divide(void), Mod(void), Add(void),
Compare(int); Compare(int);
static int MakeValue (char *s, Value *v, Var *locals); static int MakeValue (char *s, Value *v, Var *locals);
static int ParseLiteralDate (char **s, int *jul); static int ParseLiteralDate (char **s, int *jul, int *tim);
/* Binary operators - all left-associative */ /* Binary operators - all left-associative */
@@ -468,10 +468,15 @@ static int MakeValue(char *s, Value *v, Var *locals)
return OK; return OK;
} else if (*s == '\'') { /* It's a literal date */ } else if (*s == '\'') { /* It's a literal date */
s++; s++;
if ((r=ParseLiteralDate(&s, &h))) return r; if ((r=ParseLiteralDate(&s, &h, &m))) return r;
if (*s != '\'') return E_BAD_DATE; if (*s != '\'') return E_BAD_DATE;
v->type = DATE_TYPE; if (m == NO_TIME) {
v->v.val = h; v->type = DATE_TYPE;
v->v.val = h;
} else {
v->type = DATETIME_TYPE;
v->v.val = (h * 1440) + m;
}
return OK; return OK;
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/ } else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
len = 0; len = 0;
@@ -529,13 +534,34 @@ static int MakeValue(char *s, Value *v, Var *locals)
/***************************************************************/ /***************************************************************/
int DoCoerce(char type, Value *v) int DoCoerce(char type, Value *v)
{ {
int h, d, m, y, i; int h, d, m, y, i, k;
char *s; char *s;
/* Do nothing if value is already the right type */ /* Do nothing if value is already the right type */
if (type == v->type) return OK; if (type == v->type) return OK;
switch(type) { switch(type) {
case DATETIME_TYPE:
switch(v->type) {
case INT_TYPE:
v->type = DATETIME_TYPE;
return OK;
case DATE_TYPE:
v->type = DATETIME_TYPE;
v->v.val *= 1440;
return OK;
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATETIME_TYPE;
free(v->v.str);
if (m == NO_TIME) m = 0;
v->v.val = i * 1440 + m;
return OK;
default:
return E_CANT_COERCE;
}
case STR_TYPE: case STR_TYPE:
switch(v->type) { switch(v->type) {
case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break; case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
@@ -546,6 +572,15 @@ int DoCoerce(char type, Value *v)
sprintf(CoerceBuf, "%04d%c%02d%c%02d", sprintf(CoerceBuf, "%04d%c%02d%c%02d",
y, DATESEP, m+1, DATESEP, d); y, DATESEP, m+1, DATESEP, d);
break; break;
case DATETIME_TYPE:
i = v->v.val / 1440;
FromJulian(i, &y, &m, &d);
k = v->v.val % 1440;
h = k / 60;
i = k % 60;
sprintf(CoerceBuf, "%04d%c%02d%c%02d %02d%c%02d",
y, DATESEP, m+1, DATESEP, d, h, TIMESEP, i);
break;
default: return E_CANT_COERCE; default: return E_CANT_COERCE;
} }
v->type = STR_TYPE; v->type = STR_TYPE;
@@ -582,6 +617,7 @@ int DoCoerce(char type, Value *v)
case DATE_TYPE: case DATE_TYPE:
case TIM_TYPE: case TIM_TYPE:
case DATETIME_TYPE:
v->type = INT_TYPE; v->type = INT_TYPE;
return OK; return OK;
@@ -598,19 +634,25 @@ int DoCoerce(char type, Value *v)
case STR_TYPE: case STR_TYPE:
s = v->v.str; s = v->v.str;
if (ParseLiteralDate(&s, &i)) return E_CANT_COERCE; if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE; if (*s) return E_CANT_COERCE;
v->type = DATE_TYPE; v->type = DATE_TYPE;
free(v->v.str); free(v->v.str);
v->v.val = i; v->v.val = i;
return OK; return OK;
case DATETIME_TYPE:
v->type = DATE_TYPE;
v->v.val /= 1440;
return OK;
default: return E_CANT_COERCE; default: return E_CANT_COERCE;
} }
case TIM_TYPE: case TIM_TYPE:
switch(v->type) { switch(v->type) {
case INT_TYPE: case INT_TYPE:
case DATETIME_TYPE:
v->type = TIM_TYPE; v->type = TIM_TYPE;
v->v.val %= 1440; v->v.val %= 1440;
if (v->v.val < 0) v->v.val += 1440; if (v->v.val < 0) v->v.val += 1440;
@@ -680,6 +722,16 @@ static int Add(void)
return OK; return OK;
} }
/* If it's a datetime plus an int, add 'em */
if ((v1.type == DATETIME_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == DATETIME_TYPE)) {
v1.v.val += v2.v.val;
if (v1.v.val < 0) return E_DATE_OVER;
v1.type = DATETIME_TYPE;
PushValStack(v1);
return OK;
}
/* If it's a time plus an int, add 'em mod 1440 */ /* If it's a time plus an int, add 'em mod 1440 */
if ((v1.type == TIM_TYPE && v2.type == INT_TYPE) || if ((v1.type == TIM_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == TIM_TYPE)) { (v1.type == INT_TYPE && v2.type == TIM_TYPE)) {
@@ -750,6 +802,14 @@ static int Subtract(void)
return OK; return OK;
} }
/* If it's a datetime minus an int, do subtraction, checking for underflow */
if (v1.type == DATETIME_TYPE && v2.type == INT_TYPE) {
v1.v.val -= v2.v.val;
if (v1.v.val < 0) return E_DATE_OVER;
PushValStack(v1);
return OK;
}
/* If it's a time minus an int, do subtraction mod 1440 */ /* If it's a time minus an int, do subtraction mod 1440 */
if (v1.type == TIM_TYPE && v2.type == INT_TYPE) { if (v1.type == TIM_TYPE && v2.type == INT_TYPE) {
v1.v.val = (v1.v.val - v2.v.val) % 1440; v1.v.val = (v1.v.val - v2.v.val) % 1440;
@@ -1059,6 +1119,11 @@ void PrintValue (Value *v, FILE *fp)
FromJulian(v->v.val, &y, &m, &d); FromJulian(v->v.val, &y, &m, &d);
fprintf(fp, "%04d%c%02d%c%02d", y, DATESEP, m+1, DATESEP, d); fprintf(fp, "%04d%c%02d%c%02d", y, DATESEP, m+1, DATESEP, d);
} }
else if (v->type == DATETIME_TYPE) {
FromJulian(v->v.val / 1440, &y, &m, &d);
fprintf(fp, "%04d%c%02d%c%02d %02d%c%02d", y, DATESEP, m+1, DATESEP, d,
(v->v.val % 1440) / 60, TIMESEP, (v->v.val % 1440) % 60);
}
else fprintf(fp, "ERR"); else fprintf(fp, "ERR");
} }
@@ -1086,15 +1151,19 @@ int CopyValue(Value *dest, const Value *src)
/* */ /* */
/* ParseLiteralDate */ /* ParseLiteralDate */
/* */ /* */
/* Parse a literal date. Return result in jul, update s. */ /* Parse a literal date or datetime. Return result in jul */
/* and tim; update s. */
/* */ /* */
/***************************************************************/ /***************************************************************/
static int ParseLiteralDate(char **s, int *jul) static int ParseLiteralDate(char **s, int *jul, int *tim)
{ {
int y, m, d; int y, m, d;
int hour, min;
y=0; m=0; d=0; y=0; m=0; d=0;
hour=0; min=0;
*tim = NO_TIME;
if (!isdigit(**s)) return E_BAD_DATE; if (!isdigit(**s)) return E_BAD_DATE;
while (isdigit(**s)) { while (isdigit(**s)) {
y *= 10; y *= 10;
@@ -1119,6 +1188,23 @@ static int ParseLiteralDate(char **s, int *jul)
*jul = Julian(y, m, d); *jul = Julian(y, m, d);
/* Do we have a time part as well? */
if (**s == ' ') {
(*s)++;
while(isdigit(**s)) {
hour *= 10;
hour += *(*s)++ - '0';
}
if (**s != ':' && **s != '.' && **s != TIMESEP) return E_BAD_TIME;
(*s)++;
while(isdigit(**s)) {
min *= 10;
min += *(*s)++ - '0';
}
if (hour > 23 || min > 59) return E_BAD_TIME;
*tim = hour * 60 + min;
}
return OK; return OK;
} }

View File

@@ -10,14 +10,15 @@
/* */ /* */
/***************************************************************/ /***************************************************************/
/* $Id: expr.h,v 1.4 2000-02-18 03:45:53 dfs Exp $ */ /* $Id: expr.h,v 1.5 2007-06-28 03:04:44 dfs Exp $ */
/* Define the types of values */ /* Define the types of values */
#define ERR_TYPE 0 #define ERR_TYPE 0
#define INT_TYPE 1 #define INT_TYPE 1
#define TIM_TYPE 2 #define TIM_TYPE 2
#define DATE_TYPE 3 #define DATE_TYPE 3
#define STR_TYPE 4 #define STR_TYPE 4
#define DATETIME_TYPE 5
/* Define stuff for parsing expressions */ /* Define stuff for parsing expressions */
#define BEG_OF_EXPR '[' #define BEG_OF_EXPR '['

View File

@@ -12,7 +12,7 @@
/***************************************************************/ /***************************************************************/
#include "config.h" #include "config.h"
static char const RCSID[] = "$Id: funcs.c,v 1.10 2005-09-30 03:29:32 dfs Exp $"; static char const RCSID[] = "$Id: funcs.c,v 1.11 2007-06-28 03:04:44 dfs Exp $";
#include <stdio.h> #include <stdio.h>
@@ -415,6 +415,7 @@ static int FCoerce(void)
else if (! StrCmpi(s, "date")) return DoCoerce(DATE_TYPE, &RetVal); else if (! StrCmpi(s, "date")) return DoCoerce(DATE_TYPE, &RetVal);
else if (! StrCmpi(s, "time")) return DoCoerce(TIM_TYPE, &RetVal); else if (! StrCmpi(s, "time")) return DoCoerce(TIM_TYPE, &RetVal);
else if (! StrCmpi(s, "string")) return DoCoerce(STR_TYPE, &RetVal); else if (! StrCmpi(s, "string")) return DoCoerce(STR_TYPE, &RetVal);
else if (! StrCmpi(s, "datetime")) return DoCoerce(DATETIME_TYPE, &RetVal);
else return E_CANT_COERCE; else return E_CANT_COERCE;
} }