almost have both query types working

This commit is contained in:
Ron Pedde 2006-03-10 23:41:13 +00:00
parent e1c98c5fda
commit 4964fb1374
6 changed files with 182 additions and 86 deletions

View File

@ -23,6 +23,7 @@
#define _DB_GENERIC_H_ #define _DB_GENERIC_H_
#include "mp3-scanner.h" /** for MP3FILE */ #include "mp3-scanner.h" /** for MP3FILE */
#include "smart-parser.h" /** for PARSETREE */
typedef enum { typedef enum {
// generic meta data // generic meta data
@ -77,11 +78,11 @@ typedef enum {
metaItmsGenreId, metaItmsGenreId,
metaItmsStorefrontId, metaItmsStorefrontId,
metaItunesSmartPlaylist, metaItunesSmartPlaylist,
/* iTunes 5.0 + */ /* iTunes 5.0 + */
metaSongContentRating, metaSongContentRating,
metaHasChildContainers, metaHasChildContainers,
/* iTunes 6.0.2+ */ /* iTunes 6.0.2+ */
metaItunesHasVideo, metaItunesHasVideo,
@ -125,7 +126,7 @@ typedef struct tag_dbqueryinfo {
int session_id; int session_id;
int uri_count; int uri_count;
char *uri_sections[10]; char *uri_sections[10];
char *whereclause; PARSETREE pt;
void *output_info; void *output_info;
} DBQUERYINFO; } DBQUERYINFO;

View File

@ -233,28 +233,28 @@ int db_sql_parse_smart(char **pe, char **clause, char *phrase) {
*clause = strdup("1"); *clause = strdup("1");
return TRUE; return TRUE;
} }
pt=sp_init(); pt=sp_init();
if(!pt) { if(!pt) {
if(pe) *pe = strdup("Could not initialize parse tree"); if(pe) *pe = strdup("Could not initialize parse tree");
return FALSE; return FALSE;
} }
if(!sp_parse(pt,phrase)) { if(!sp_parse(pt,phrase,SP_TYPE_PLAYLIST)) {
if(pe) *pe = strdup(sp_get_error(pt)); if(pe) *pe = strdup(sp_get_error(pt));
DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt)); DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt));
sp_dispose(pt); sp_dispose(pt);
return FALSE; return FALSE;
} else { } else {
*clause = sp_sql_clause(pt); *clause = sp_sql_clause(pt);
} }
sp_dispose(pt); sp_dispose(pt);
return TRUE; return TRUE;
} }
/** /**
* open sqlite database * open sqlite database
* *
@ -620,7 +620,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
/* Always an add if in song scan on full reload */ /* Always an add if in song scan on full reload */
if((!db_sql_reload)||(!db_sql_in_scan)) { if((!db_sql_reload)||(!db_sql_in_scan)) {
err=db_sql_fetch_int(NULL,&count,"select count(*) from songs where " err=db_sql_fetch_int(NULL,&count,"select count(*) from songs where "
"path='%q'",pmp3->path); "path='%q'",pmp3->path);
@ -630,7 +630,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
DPRINTF(E_LOG,L_DB,"Error: %s\n",pe); DPRINTF(E_LOG,L_DB,"Error: %s\n",pe);
return err; return err;
} }
} }
pmp3->play_count=0; pmp3->play_count=0;
@ -731,7 +731,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
if(id) if(id)
*id = insertid; *id = insertid;
DPRINTF(E_SPAM,L_DB,"Exiting db_sql_add\n"); DPRINTF(E_SPAM,L_DB,"Exiting db_sql_add\n");
return DB_E_SUCCESS; return DB_E_SUCCESS;
} }
@ -931,6 +931,7 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
char query_count[255]; char query_count[255];
char query_rest[4096]; char query_rest[4096];
char *where_clause; char *where_clause;
char *filter;
int is_smart; int is_smart;
int have_clause=0; int have_clause=0;
@ -980,13 +981,13 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
if(is_smart) { if(is_smart) {
if(!db_sql_parse_smart(NULL,&where_clause,temprow[1])) if(!db_sql_parse_smart(NULL,&where_clause,temprow[1]))
where_clause = strdup("0"); where_clause = strdup("0");
if(!where_clause) { if(!where_clause) {
db_sql_enum_end_fn(NULL); db_sql_enum_end_fn(NULL);
db_get_error(pe,DB_E_PARSE); db_get_error(pe,DB_E_PARSE);
return DB_E_PARSE; return DB_E_PARSE;
} }
sprintf(query_select,"select * from songs "); sprintf(query_select,"select * from songs ");
sprintf(query_count,"select count(id) from songs "); sprintf(query_count,"select count(id) from songs ");
sprintf(query_rest,"where (%s)",where_clause); sprintf(query_rest,"where (%s)",where_clause);
@ -1048,18 +1049,25 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
} }
/* Apply the query/filter */ /* Apply the query/filter */
if(pinfo->whereclause) { if(pinfo->pt) {
if(have_clause) filter = sp_sql_clause(pinfo->pt);
strcat(query_rest," and ");
else
strcpy(query_rest," where ");
strcat(query_rest,"("); if(filter) {
strcat(query_rest,pinfo->whereclause); if(have_clause) {
strcat(query_rest,")"); strcat(query_rest," and ");
} else {
strcpy(query_rest," where ");
}
strcat(query_rest,"(");
strcat(query_rest,filter);
strcat(query_rest,")");
free(filter);
} else {
DPRINTF(E_LOG,L_DB,"Error getting sql for parse tree\n");
}
} }
if(pinfo->index_type == indexTypeLast) { if(pinfo->index_type == indexTypeLast) {
/* We don't really care how many items unless we are /* We don't really care how many items unless we are
* doing a "last n items" query */ * doing a "last n items" query */
@ -1355,14 +1363,14 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType)) if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
/* ascd */ /* ascd */
size += 12; size += 12;
if(db_wantsmeta(pinfo->meta,metaSongContentRating)) if(db_wantsmeta(pinfo->meta,metaSongContentRating))
/* ascr */ /* ascr */
size += 9; size += 9;
if(db_wantsmeta(pinfo->meta,metaItunesHasVideo)) if(db_wantsmeta(pinfo->meta,metaItunesHasVideo))
/* aeHV */ /* aeHV */
size += 9; size += 9;
return size; return size;
break; break;
@ -1596,10 +1604,10 @@ M3UFILE *db_sql_fetch_playlist(char **pe, char *path, int index) {
db_get_error(pe,DB_E_INVALID_PLAYLIST); db_get_error(pe,DB_E_INVALID_PLAYLIST);
return NULL; return NULL;
} }
return NULL; /* sql error or something */ return NULL; /* sql error or something */
} }
pm3u=(M3UFILE*)malloc(sizeof(M3UFILE)); pm3u=(M3UFILE*)malloc(sizeof(M3UFILE));
if(!pm3u) if(!pm3u)
DPRINTF(E_FATAL,L_MISC,"malloc error: db_sql_fetch_playlist\n"); DPRINTF(E_FATAL,L_MISC,"malloc error: db_sql_fetch_playlist\n");
@ -1760,7 +1768,7 @@ int db_sql_get_count(char **pe, int *count, CountType_t type) {
*/ */
int db_sql_playcount_increment(char **pe, int id) { int db_sql_playcount_increment(char **pe, int id) {
time_t now = time(NULL); time_t now = time(NULL);
return db_sql_exec_fn(pe,E_INF,"update songs set play_count=play_count + 1" return db_sql_exec_fn(pe,E_INF,"update songs set play_count=play_count + 1"
", time_played=%d where id=%d",now,id); ", time_played=%d where id=%d",now,id);
} }

View File

@ -126,7 +126,7 @@ int daap_auth(char *username, char *password) {
return 0; return 0;
if(strcasecmp(password,readpassword)) { if(strcasecmp(password,readpassword)) {
DPRINTF(E_LOG,L_DAAP | L_WS,"Bad password attempt\n"); DPRINTF(E_LOG,L_DAAP | L_WS,"Bad password attempt\n");
return 0; return 0;
} }
@ -152,13 +152,20 @@ void daap_handler(WS_CONNINFO *pwsc) {
memset(pqi,0x00,sizeof(DBQUERYINFO)); memset(pqi,0x00,sizeof(DBQUERYINFO));
/* we could really pre-parse this to make sure it works */
query=ws_getvar(pwsc,"query"); query=ws_getvar(pwsc,"query");
if(!query) query=ws_getvar(pwsc,"filter"); if(!query) query=ws_getvar(pwsc,"filter");
if(query) { if(query) {
DPRINTF(E_DBG,L_DAAP,"Getting sql clause for %s\n",query); pqi->pt = sp_init();
pqi->whereclause = query_build_sql(query); if(!sp_parse(&pqi->pt,query,SP_TYPE_QUERY)) {
DPRINTF(E_LOG,L_DAAP,"Ignoring bad query/filter (%s): %s\n",
query,sp_get_error(pqi->pt));
sp_dispose(pqi->pt);
pqi->pt = NULL;
}
} }
/* Add some default headers */ /* Add some default headers */
ws_addresponseheader(pwsc,"Accept-Ranges","bytes"); ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/" VERSION); ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/" VERSION);

View File

@ -11,19 +11,23 @@
#include "smart-parser.h" #include "smart-parser.h"
void usage(void) { void usage(void) {
printf("Usage:\n\n parser [-d <debug level>] \"phrase\"\n\n"); printf("Usage:\n\n parser [-t <type (0/1)>] [-d <debug level>] \"phrase\"\n\n");
exit(0); exit(0);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int option; int option;
int type=0;
PARSETREE pt; PARSETREE pt;
while((option = getopt(argc, argv, "d:")) != -1) { while((option = getopt(argc, argv, "d:t:")) != -1) {
switch(option) { switch(option) {
case 'd': case 'd':
err_setlevel(atoi(optarg)); err_setlevel(atoi(optarg));
break; break;
case 't':
type = atoi(optarg);
break;
default: default:
fprintf(stderr,"Error: unknown option (%c)\n\n",option); fprintf(stderr,"Error: unknown option (%c)\n\n",option);
usage(); usage();
@ -34,7 +38,7 @@ int main(int argc, char *argv[]) {
printf("Parsing %s\n",argv[optind]); printf("Parsing %s\n",argv[optind]);
pt=sp_init(); pt=sp_init();
if(!sp_parse(pt,argv[optind])) { if(!sp_parse(pt,argv[optind],type)) {
printf("%s\n",sp_get_error(pt)); printf("%s\n",sp_get_error(pt));
} else { } else {
printf("SQL: %s\n",sp_sql_clause(pt)); printf("SQL: %s\n",sp_sql_clause(pt));

View File

@ -147,6 +147,10 @@ typedef struct tag_sp_node {
#define T_ENDSWITH 0x001d #define T_ENDSWITH 0x001d
#define T_LAST 0x001e #define T_LAST 0x001e
/* specific to query extensions */
#define T_GREATERAND 0x001f
#define T_EXPRQUOTE 0x0020
#define T_EOF 0x00fd #define T_EOF 0x00fd
#define T_BOF 0x00fe #define T_BOF 0x00fe
#define T_ERROR 0x00ff #define T_ERROR 0x00ff
@ -211,6 +215,15 @@ FIELDLOOKUP sp_symbols_0[] = {
}; };
FIELDLOOKUP sp_symbols_1[] = { FIELDLOOKUP sp_symbols_1[] = {
{ T_OPENPAREN, "(", NULL },
{ T_CLOSEPAREN, ")", NULL },
{ T_EXPRQUOTE, "'", NULL },
{ T_GREATERAND, "+", NULL },
{ T_GREATERAND, " ", NULL },
{ T_LESS,"-", NULL },
{ T_OR, ",", NULL },
{ T_EQUAL, ":", NULL },
{ T_NOT, "!", NULL },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
@ -283,31 +296,31 @@ FIELDLOOKUP sp_fields_0[] = {
}; };
FIELDLOOKUP sp_fields_1[] = { FIELDLOOKUP sp_fields_1[] = {
{ T_STRING_FIELD, "dmap.itemname", "title" }, { T_STRING_FIELD, "dmap.itemname", "title" },
{ T_INT_FIELD, "dmap.itemid", "id" }, { T_INT_FIELD, "dmap.itemid", "id" },
{ T_STRING_FIELD, "daap.songalbum", "album" }, { T_STRING_FIELD, "daap.songalbum", "album" },
{ T_STRING_FIELD, "daap.songartist", "artist" }, { T_STRING_FIELD, "daap.songartist", "artist" },
{ T_INT_FIELD, "daap.songbitrate", "bitrate" }, { T_INT_FIELD, "daap.songbitrate", "bitrate" },
{ T_STRING_FIELD, "daap.songcomment", "comment" }, { T_STRING_FIELD, "daap.songcomment", "comment" },
{ T_INT_FIELD, "daap.songcompilation", "compilation" }, { T_INT_FIELD, "daap.songcompilation", "compilation" },
{ T_STRING_FIELD, "daap.songcomposer", "composer" }, { T_STRING_FIELD, "daap.songcomposer", "composer" },
{ T_INT_FIELD, "daap.songdatakind", "data_kind" }, { T_INT_FIELD, "daap.songdatakind", "data_kind" },
{ T_STRING_FIELD, "daap.songdataurl", "url" }, { T_STRING_FIELD, "daap.songdataurl", "url" },
{ T_INT_FIELD, "daap.songdateadded", "time_added" }, { T_INT_FIELD, "daap.songdateadded", "time_added" },
{ T_INT_FIELD, "daap.songdatemodified","time_modified" }, { T_INT_FIELD, "daap.songdatemodified", "time_modified" },
{ T_STRING_FIELD, "daap.songdescription", "description" }, { T_STRING_FIELD, "daap.songdescription", "description" },
{ T_INT_FIELD, "daap.songdisccount", "total_discs" }, { T_INT_FIELD, "daap.songdisccount", "total_discs" },
{ T_INT_FIELD, "daap.songdiscnumber", "disc" }, { T_INT_FIELD, "daap.songdiscnumber", "disc" },
{ T_STRING_FIELD, "daap.songformat", "type" }, { T_STRING_FIELD, "daap.songformat", "type" },
{ T_STRING_FIELD, "daap.songgenre", "genre" }, { T_STRING_FIELD, "daap.songgenre", "genre" },
{ T_INT_FIELD, "daap.songsamplerate", "samplerate" }, { T_INT_FIELD, "daap.songsamplerate", "samplerate" },
{ T_INT_FIELD, "daap.songsize", "file_size" }, { T_INT_FIELD, "daap.songsize", "file_size" },
// { T_INT_FIELD, "daap.songstarttime", 0 }, // { T_INT_FIELD, "daap.songstarttime", 0 },
{ T_INT_FIELD, "daap.songstoptime", "song_length" }, { T_INT_FIELD, "daap.songstoptime", "song_length" },
{ T_INT_FIELD, "daap.songtime", "song_length" }, { T_INT_FIELD, "daap.songtime", "song_length" },
{ T_INT_FIELD, "daap.songtrackcount", "total_tracks" }, { T_INT_FIELD, "daap.songtrackcount", "total_tracks" },
{ T_INT_FIELD, "daap.songtracknumber", "track" }, { T_INT_FIELD, "daap.songtracknumber", "track" },
{ T_INT_FIELD, "daap.songyear", "year" }, { T_INT_FIELD, "daap.songyear", "year" },
{ 0, NULL, NULL } { 0, NULL, NULL }
}; };
@ -341,6 +354,7 @@ typedef struct tag_parsetree {
#define SP_E_BEFOREAFTER 0x0a #define SP_E_BEFOREAFTER 0x0a
#define SP_E_TIMEINTERVAL 0x0b #define SP_E_TIMEINTERVAL 0x0b
#define SP_E_DATE 0x0c #define SP_E_DATE 0x0c
#define SP_E_EXPRQUOTE 0x0d
char *sp_errorstrings[] = { char *sp_errorstrings[] = {
"Success", "Success",
@ -355,7 +369,8 @@ char *sp_errorstrings[] = {
"Expecting date comparison operator (<,<=,>,>=)", "Expecting date comparison operator (<,<=,>,>=)",
"Expecting interval comparison (before, after)", "Expecting interval comparison (before, after)",
"Expecting time interval (days, weeks, months, years)", "Expecting time interval (days, weeks, months, years)",
"Expecting date" "Expecting date",
"Expecting ' (single quote)\n"
}; };
/* Forwards */ /* Forwards */
@ -431,7 +446,10 @@ time_t sp_isdate(char *string) {
} }
/** /**
* scan the input, returning the next available token. * scan the input, returning the next available token. This is
* kind of a mess, and looking at it with new eyes would probably
* yield a better way of tokenizing the stream, but this seems to
* work.
* *
* @param tree current working parse tree. * @param tree current working parse tree.
* @returns next token (token, not the value) * @returns next token (token, not the value)
@ -446,6 +464,7 @@ int sp_scan(PARSETREE tree, int hint) {
int is_qstr; int is_qstr;
time_t tval; time_t tval;
char *qstr; char *qstr;
char *token_string;
if(tree->token.token_id & 0x2000) { if(tree->token.token_id & 0x2000) {
if(tree->token.data.cvalue) if(tree->token.data.cvalue)
@ -483,7 +502,7 @@ int sp_scan(PARSETREE tree, int hint) {
DPRINTF(E_SPAM,L_PARSE,"Starting scan - in_string: %d, hint: %d\n", DPRINTF(E_SPAM,L_PARSE,"Starting scan - in_string: %d, hint: %d\n",
tree->in_string, hint); tree->in_string, hint);
/* check symbols */ /* check symbols */
if(!tree->in_string) { if(!tree->in_string) {
@ -501,17 +520,21 @@ int sp_scan(PARSETREE tree, int hint) {
qstr = sp_terminators[tree->token_list][3]; qstr = sp_terminators[tree->token_list][3];
is_qstr = (strchr(qstr,*(tree->current)) != NULL); is_qstr = (strchr(qstr,*(tree->current)) != NULL);
DPRINTF(E_SPAM,L_PARSE,"qstr: %s -- is_quoted: %d\n",qstr,is_qstr);
if(strlen(qstr)) { /* strings ARE quoted */ if(strlen(qstr)) { /* strings ARE quoted */
if(hint == SP_HINT_STRING) { /* MUST be a quote */ if(hint == SP_HINT_STRING) { /* MUST be a quote */
if(!is_qstr) { if(!is_qstr) {
tree->token.token_id = T_ERROR;
return T_ERROR; return T_ERROR;
} }
} else { } else {
if(is_qstr) { if(is_qstr) {
tree->in_string = 1; /* guess we're in a string */ tree->in_string = 1; /* guess we're in a string */
terminator=sp_terminators[tree->token_list][1]; terminator=sp_terminators[tree->token_list][1];
tree->current++; tree->current++;
} }
} }
} }
@ -534,7 +557,7 @@ int sp_scan(PARSETREE tree, int hint) {
/* find it in the token list */ /* find it in the token list */
pfield=sp_fields[tree->token_list]; pfield=sp_fields[tree->token_list];
while(pfield->name) { while(pfield->name) {
DPRINTF(E_SPAM,L_PARSE,"Comparing to %s\n",pfield->name); DPRINTF(E_SPAM,L_PARSE,"Comparing to %s\n",pfield->name);
if(strlen(pfield->name) == len) { if(strlen(pfield->name) == len) {
if(strncasecmp(pfield->name,tree->current,len) == 0) { if(strncasecmp(pfield->name,tree->current,len) == 0) {
found=1; found=1;
@ -552,12 +575,20 @@ int sp_scan(PARSETREE tree, int hint) {
} }
if(tree->token.token_id & 0x2000) { if(tree->token.token_id & 0x2000) {
token_string=tree->current;
if(found) {
if(pfield->xlat) {
len = strlen(pfield->xlat);
token_string = pfield->xlat;
}
}
tree->token.data.cvalue = malloc(len + 1); tree->token.data.cvalue = malloc(len + 1);
if(!tree->token.data.cvalue) { if(!tree->token.data.cvalue) {
/* fail on malloc error */ /* fail on malloc error */
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n"); DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
} }
strncpy(tree->token.data.cvalue,tree->current,len); strncpy(tree->token.data.cvalue,token_string,len);
tree->token.data.cvalue[len] = '\x0'; tree->token.data.cvalue[len] = '\x0';
} }
@ -591,15 +622,15 @@ int sp_scan(PARSETREE tree, int hint) {
is_qstr = (strchr(qstr,*tree->current) != NULL); is_qstr = (strchr(qstr,*tree->current) != NULL);
if((!found) && strlen(qstr) && (tree->in_string)) { if((!found) && strlen(qstr) && (tree->in_string)) {
if(is_qstr) { if(is_qstr) {
tree->current++; /* absorb it */ tree->current++; /* absorb it */
} else { } else {
DPRINTF(E_INF,L_PARSE,"Missing closing quotes\n"); DPRINTF(E_INF,L_PARSE,"Missing closing quotes\n");
if(tree->token.token_id & 0x2000) { if(tree->token.token_id & 0x2000) {
free(tree->token.data.cvalue); free(tree->token.data.cvalue);
} }
tree->token.token_id = T_ERROR; tree->token.token_id = T_ERROR;
} }
} }
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ", DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
@ -652,10 +683,11 @@ PARSETREE sp_init(void) {
* @param term term or phrase to parse * @param term term or phrase to parse
* @returns 1 if successful, 0 if not * @returns 1 if successful, 0 if not
*/ */
int sp_parse(PARSETREE tree, char *term) { int sp_parse(PARSETREE tree, char *term, int type) {
tree->term = strdup(term); /* will be destroyed by parsing */ tree->term = strdup(term); /* will be destroyed by parsing */
tree->current=tree->term; tree->current=tree->term;
tree->token.token_id=T_BOF; tree->token.token_id=T_BOF;
tree->token_list = type;
if(tree->tree) if(tree->tree)
sp_free_node(tree->tree); sp_free_node(tree->tree);
@ -716,7 +748,8 @@ SP_NODE *sp_parse_aexpr(PARSETREE tree) {
expr = sp_parse_expr(tree); expr = sp_parse_expr(tree);
while(expr && (tree->token.token_id == T_AND)) { while(expr && ((tree->token.token_id == T_AND) ||
(tree->token.token_id == T_GREATERAND))) {
pnew = (SP_NODE*)malloc(sizeof(SP_NODE)); pnew = (SP_NODE*)malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error\n"); DPRINTF(E_FATAL,L_PARSE,"Malloc error\n");
@ -829,6 +862,15 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
sp_enter_exit(tree,"sp_parse_criterion",1,expr); sp_enter_exit(tree,"sp_parse_criterion",1,expr);
if(tree->token_list == 1) {
if(tree->token.token_id != T_EXPRQUOTE) {
sp_set_error(tree,SP_E_EXPRQUOTE);
return NULL;
} else {
sp_scan(tree,SP_HINT_NONE);
}
}
switch(tree->token.token_id) { switch(tree->token.token_id) {
case T_STRING_FIELD: case T_STRING_FIELD:
expr = sp_parse_string_criterion(tree); expr = sp_parse_string_criterion(tree);
@ -849,6 +891,16 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
break; break;
} }
if(tree->token_list == 1) {
if(tree->token.token_id != T_EXPRQUOTE) {
sp_set_error(tree,SP_E_EXPRQUOTE);
sp_free_node(expr);
return NULL;
} else {
sp_scan(tree,SP_HINT_NONE);
}
}
sp_enter_exit(tree,"sp_parse_criterion",0,expr); sp_enter_exit(tree,"sp_parse_criterion",0,expr);
return expr; return expr;
} }
@ -872,7 +924,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
memset(pnew,0x00,sizeof(SP_NODE)); memset(pnew,0x00,sizeof(SP_NODE));
pnew->left.field = strdup(tree->token.data.cvalue); pnew->left.field = strdup(tree->token.data.cvalue);
sp_scan(tree,SP_HINT_NONE);/* scan past the string field we know is there */ sp_scan(tree,SP_HINT_NONE); /* scan past the string field we know is there */
if(tree->token.token_id == T_NOT) { if(tree->token.token_id == T_NOT) {
pnew->not_flag=1; pnew->not_flag=1;
@ -895,11 +947,22 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
} }
if(result) { if(result) {
sp_scan(tree,SP_HINT_NONE); sp_scan(tree,SP_HINT_STRING);
/* should be sitting on string literal */ /* should be sitting on string literal */
if(tree->token.token_id == T_STRING) { if(tree->token.token_id == T_STRING) {
result = 1; result = 1;
pnew->right.cvalue=strdup(tree->token.data.cvalue); pnew->right.cvalue=strdup(tree->token.data.cvalue);
if(tree->token_list == 1) {
if(pnew->right.cvalue[0]=='*') {
pnew->op = T_ENDSWITH;
memcpy(pnew->right.cvalue,&pnew->right.cvalue[1],
(int)strlen(pnew->right.cvalue)); /* with zt */
}
if(pnew->right.cvalue[strlen(pnew->right.cvalue)-1] == '*') {
pnew->op = (pnew->op==T_ENDSWITH)?T_INCLUDES:T_STARTSWITH;
pnew->right.cvalue[strlen(pnew->right.cvalue)-1] = '\0';
}
}
sp_scan(tree,SP_HINT_NONE); sp_scan(tree,SP_HINT_NONE);
} else { } else {
sp_set_error(tree,SP_E_OPENQUOTE); sp_set_error(tree,SP_E_OPENQUOTE);
@ -954,6 +1017,11 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
pnew->op=tree->token.token_id; pnew->op=tree->token.token_id;
pnew->op_type = SP_OPTYPE_INT; pnew->op_type = SP_OPTYPE_INT;
break; break;
case T_GREATERAND:
result = 1;
pnew->op = T_GREATER;
pnew->op_type = SP_OPTYPE_INT;
break;
default: default:
/* Error: expecting legal int comparison operator */ /* Error: expecting legal int comparison operator */
sp_set_error(tree,SP_E_INTCMP); sp_set_error(tree,SP_E_INTCMP);
@ -963,7 +1031,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
} }
if(result) { if(result) {
sp_scan(tree,SP_HINT_NONE); sp_scan(tree,SP_HINT_INT);
/* should be sitting on a literal string */ /* should be sitting on a literal string */
if(tree->token.token_id == T_NUMBER) { if(tree->token.token_id == T_NUMBER) {
result = 1; result = 1;
@ -1023,6 +1091,11 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
pnew->op=tree->token.token_id; pnew->op=tree->token.token_id;
pnew->op_type = SP_OPTYPE_DATE; pnew->op_type = SP_OPTYPE_DATE;
break; break;
case T_GREATERAND:
result = 1;
pnew->op=T_GREATER;
pnew->op_type = SP_OPTYPE_DATE;
break;
case T_BEFORE: case T_BEFORE:
result = 1; result = 1;
pnew->op_type = SP_OPTYPE_DATE; pnew->op_type = SP_OPTYPE_DATE;
@ -1042,7 +1115,7 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
} }
if(result) { if(result) {
sp_scan(tree,SP_HINT_NONE); sp_scan(tree,SP_HINT_DATE);
/* should be sitting on a date */ /* should be sitting on a date */
if((pnew->right.tvalue = sp_parse_date(tree))) { if((pnew->right.tvalue = sp_parse_date(tree))) {
result=1; result=1;

View File

@ -8,10 +8,13 @@
typedef void* PARSETREE; typedef void* PARSETREE;
extern PARSETREE sp_init(void); extern PARSETREE sp_init(void);
extern int sp_parse(PARSETREE *tree, char *term); extern int sp_parse(PARSETREE *tree, char *term, int type);
extern int sp_dispose(PARSETREE tree); extern int sp_dispose(PARSETREE tree);
extern char *sp_get_error(PARSETREE tree); extern char *sp_get_error(PARSETREE tree);
extern char *sp_sql_clause(PARSETREE tree); extern char *sp_sql_clause(PARSETREE tree);
#define SP_TYPE_PLAYLIST 0
#define SP_TYPE_QUERY 1
#endif /* _SMART_PARSER_H_ */ #endif /* _SMART_PARSER_H_ */