mirror of
https://github.com/owntone/owntone-server.git
synced 2025-07-28 17:51:00 -04:00
Complete unifying smart playlists and query/filters
This commit is contained in:
parent
ae22cba1ae
commit
90dc66110a
@ -341,7 +341,8 @@ char *db_error_list[] = {
|
|||||||
"Invalid song id: %d",
|
"Invalid song id: %d",
|
||||||
"Parse error: %s",
|
"Parse error: %s",
|
||||||
"No backend database support for type: %s",
|
"No backend database support for type: %s",
|
||||||
"Could not initialize thread pool"
|
"Could not initialize thread pool",
|
||||||
|
"Passed buffer too small for result"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
|
@ -209,6 +209,8 @@ extern void db_dispose_playlist(M3UFILE *pm3u);
|
|||||||
#define DB_E_PARSE 0x08 /**< could not parse result */
|
#define DB_E_PARSE 0x08 /**< could not parse result */
|
||||||
#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */
|
#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */
|
||||||
#define DB_E_PROC 0x0A /**< could not start threadpool */
|
#define DB_E_PROC 0x0A /**< could not start threadpool */
|
||||||
|
#define DB_E_SIZE 0x0B /**< passed buffer too small */
|
||||||
|
|
||||||
/* describes the individual database handlers */
|
/* describes the individual database handlers */
|
||||||
typedef struct tag_dbinfo {
|
typedef struct tag_dbinfo {
|
||||||
char *handler_name;
|
char *handler_name;
|
||||||
|
38
src/db-sql.c
38
src/db-sql.c
@ -45,7 +45,6 @@
|
|||||||
#ifdef HAVE_LIBSQLITE
|
#ifdef HAVE_LIBSQLITE
|
||||||
#include "db-sql-sqlite2.h"
|
#include "db-sql-sqlite2.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBSQLITE3
|
#ifdef HAVE_LIBSQLITE3
|
||||||
#include "db-sql-sqlite3.h"
|
#include "db-sql-sqlite3.h"
|
||||||
#endif
|
#endif
|
||||||
@ -122,6 +121,38 @@ int db_sql_open_sqlite3(char **pe, char *parameters) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* escape a sql string, returning it the supplied buffer.
|
||||||
|
* note that this uses the sqlite escape format -- use %q for quoted
|
||||||
|
* sql.
|
||||||
|
*
|
||||||
|
* @param buffer buffer to throw the escaped sql into
|
||||||
|
* @param size size of buffer (or size required, if DB_E_SIZE)
|
||||||
|
* @param fmt printf style format
|
||||||
|
* @returns DB_E_SUCCESS with buffer filled, or DB_E_SIZE, with size
|
||||||
|
* set to the required size
|
||||||
|
*/
|
||||||
|
int db_sql_escape(char *buffer, int *size, char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
char *escaped;
|
||||||
|
|
||||||
|
va_start(ap,fmt);
|
||||||
|
escaped = db_sql_vmquery_fn(fmt,ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if(*size < (int)strlen(escaped)) {
|
||||||
|
*size = strlen(escaped) + 1;
|
||||||
|
db_sql_vmfree_fn(escaped);
|
||||||
|
return DB_E_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(buffer,escaped);
|
||||||
|
*size = strlen(escaped);
|
||||||
|
db_sql_vmfree_fn(escaped);
|
||||||
|
|
||||||
|
return DB_E_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fetch a single row, using the underlying database enum
|
* fetch a single row, using the underlying database enum
|
||||||
@ -1050,8 +1081,8 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
|
|
||||||
/* Apply the query/filter */
|
/* Apply the query/filter */
|
||||||
if(pinfo->pt) {
|
if(pinfo->pt) {
|
||||||
|
DPRINTF(E_DBG,L_DB,"Got query/filter\n");
|
||||||
filter = sp_sql_clause(pinfo->pt);
|
filter = sp_sql_clause(pinfo->pt);
|
||||||
|
|
||||||
if(filter) {
|
if(filter) {
|
||||||
if(have_clause) {
|
if(have_clause) {
|
||||||
strcat(query_rest," and ");
|
strcat(query_rest," and ");
|
||||||
@ -1059,13 +1090,14 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
strcpy(query_rest," where ");
|
strcpy(query_rest," where ");
|
||||||
}
|
}
|
||||||
strcat(query_rest,"(");
|
strcat(query_rest,"(");
|
||||||
|
|
||||||
strcat(query_rest,filter);
|
strcat(query_rest,filter);
|
||||||
strcat(query_rest,")");
|
strcat(query_rest,")");
|
||||||
free(filter);
|
free(filter);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(E_LOG,L_DB,"Error getting sql for parse tree\n");
|
DPRINTF(E_LOG,L_DB,"Error getting sql for parse tree\n");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
DPRINTF(E_DBG,L_DB,"No query/filter\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pinfo->index_type == indexTypeLast) {
|
if(pinfo->index_type == indexTypeLast) {
|
||||||
|
@ -34,6 +34,7 @@ extern int db_sql_open_sqlite3(char **pe, char *parameters);
|
|||||||
extern int db_sql_open(char **pe, char *parameters);
|
extern int db_sql_open(char **pe, char *parameters);
|
||||||
extern int db_sql_init(int reload);
|
extern int db_sql_init(int reload);
|
||||||
extern int db_sql_deinit(void);
|
extern int db_sql_deinit(void);
|
||||||
|
extern int db_sql_escape(char *buffer, int *size, char *fmt, ...);
|
||||||
extern int db_sql_add(char **pe, MP3FILE *pmp3, int *id);
|
extern int db_sql_add(char **pe, MP3FILE *pmp3, int *id);
|
||||||
extern int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo);
|
extern int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo);
|
||||||
extern int db_sql_enum_size(char **pe, DBQUERYINFO *pinfo, int *count, int *total_size);
|
extern int db_sql_enum_size(char **pe, DBQUERYINFO *pinfo, int *count, int *total_size);
|
||||||
|
@ -77,6 +77,7 @@ static DAAP_ITEMS *dispatch_xml_lookup_tag(char *tag);
|
|||||||
static char *dispatch_xml_encode(char *original, int len);
|
static char *dispatch_xml_encode(char *original, int len);
|
||||||
static int dispatch_output_xml_write(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, unsigned char *block, int len);
|
static int dispatch_output_xml_write(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, unsigned char *block, int len);
|
||||||
|
|
||||||
|
static void dispatch_cleanup(DBQUERYINFO *pqi);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold the inf for the output serializer
|
* Hold the inf for the output serializer
|
||||||
@ -96,6 +97,17 @@ typedef struct tag_output_info {
|
|||||||
} OUTPUT_INFO;
|
} OUTPUT_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do cleanup on the pqi structure... free any allocated memory, etc
|
||||||
|
*/
|
||||||
|
void dispatch_cleanup(DBQUERYINFO *pqi) {
|
||||||
|
if(pqi->pt) {
|
||||||
|
sp_dispose(pqi->pt);
|
||||||
|
}
|
||||||
|
free(pqi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles authentication for the daap server. This isn't the
|
* Handles authentication for the daap server. This isn't the
|
||||||
* authenticator for the web admin page, but rather the iTunes
|
* authenticator for the web admin page, but rather the iTunes
|
||||||
@ -157,12 +169,13 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
if(!query) query=ws_getvar(pwsc,"filter");
|
if(!query) query=ws_getvar(pwsc,"filter");
|
||||||
if(query) {
|
if(query) {
|
||||||
pqi->pt = sp_init();
|
pqi->pt = sp_init();
|
||||||
if(!sp_parse(&pqi->pt,query,SP_TYPE_QUERY)) {
|
if(!sp_parse(pqi->pt,query,SP_TYPE_QUERY)) {
|
||||||
DPRINTF(E_LOG,L_DAAP,"Ignoring bad query/filter (%s): %s\n",
|
DPRINTF(E_LOG,L_DAAP,"Ignoring bad query/filter (%s): %s\n",
|
||||||
query,sp_get_error(pqi->pt));
|
query,sp_get_error(pqi->pt));
|
||||||
sp_dispose(pqi->pt);
|
sp_dispose(pqi->pt);
|
||||||
pqi->pt = NULL;
|
pqi->pt = NULL;
|
||||||
}
|
}
|
||||||
|
DPRINTF(E_DBG,L_DAAP,"Parsed query successfully\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -173,15 +186,6 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
ws_addresponseheader(pwsc,"Cache-Control","no-cache"); /* anti-ie defense */
|
ws_addresponseheader(pwsc,"Cache-Control","no-cache"); /* anti-ie defense */
|
||||||
ws_addresponseheader(pwsc,"Expires","-1");
|
ws_addresponseheader(pwsc,"Expires","-1");
|
||||||
|
|
||||||
/* This we should put in a quirks file or something, but here might
|
|
||||||
* be a decent workaround for various failures on different clients */
|
|
||||||
/* nm... backing this out. Really do need a "quirks" mode
|
|
||||||
pwsc->close=0;
|
|
||||||
if(ws_testrequestheader(pwsc,"Connection","Close")) {
|
|
||||||
pwsc->close = 1;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(ws_getvar(pwsc,"session-id"))
|
if(ws_getvar(pwsc,"session-id"))
|
||||||
pqi->session_id = atoi(ws_getvar(pwsc,"session-id"));
|
pqi->session_id = atoi(ws_getvar(pwsc,"session-id"));
|
||||||
|
|
||||||
@ -195,26 +199,31 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
/* Start dispatching */
|
/* Start dispatching */
|
||||||
if(!strcasecmp(pqi->uri_sections[0],"server-info")) {
|
if(!strcasecmp(pqi->uri_sections[0],"server-info")) {
|
||||||
dispatch_server_info(pwsc,pqi);
|
dispatch_server_info(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcasecmp(pqi->uri_sections[0],"content-codes")) {
|
if(!strcasecmp(pqi->uri_sections[0],"content-codes")) {
|
||||||
dispatch_content_codes(pwsc,pqi);
|
dispatch_content_codes(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcasecmp(pqi->uri_sections[0],"login")) {
|
if(!strcasecmp(pqi->uri_sections[0],"login")) {
|
||||||
dispatch_login(pwsc,pqi);
|
dispatch_login(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcasecmp(pqi->uri_sections[0],"update")) {
|
if(!strcasecmp(pqi->uri_sections[0],"update")) {
|
||||||
dispatch_update(pwsc,pqi);
|
dispatch_update(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcasecmp(pqi->uri_sections[0],"logout")) {
|
if(!strcasecmp(pqi->uri_sections[0],"logout")) {
|
||||||
dispatch_logout(pwsc,pqi);
|
dispatch_logout(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +237,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
if(!strcasecmp(pqi->uri_sections[0],"databases")) {
|
if(!strcasecmp(pqi->uri_sections[0],"databases")) {
|
||||||
if(pqi->uri_count == 1) {
|
if(pqi->uri_count == 1) {
|
||||||
dispatch_dbinfo(pwsc,pqi);
|
dispatch_dbinfo(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pqi->db_id=atoi(pqi->uri_sections[1]);
|
pqi->db_id=atoi(pqi->uri_sections[1]);
|
||||||
@ -235,16 +245,18 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
||||||
/* /databases/id/items */
|
/* /databases/id/items */
|
||||||
dispatch_items(pwsc,pqi);
|
dispatch_items(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!strcasecmp(pqi->uri_sections[2],"containers")) {
|
if(!strcasecmp(pqi->uri_sections[2],"containers")) {
|
||||||
/* /databases/id/containers */
|
/* /databases/id/containers */
|
||||||
dispatch_playlists(pwsc,pqi);
|
dispatch_playlists(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwsc->close=1;
|
pwsc->close=1;
|
||||||
free(pqi);
|
dispatch_cleanup(pqi);
|
||||||
ws_returnerror(pwsc,404,"Page not found");
|
ws_returnerror(pwsc,404,"Page not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -252,34 +264,39 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
if(!strcasecmp(pqi->uri_sections[2],"browse")) {
|
if(!strcasecmp(pqi->uri_sections[2],"browse")) {
|
||||||
/* /databases/id/browse/something */
|
/* /databases/id/browse/something */
|
||||||
dispatch_browse(pwsc,pqi);
|
dispatch_browse(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
if(!strcasecmp(pqi->uri_sections[2],"items")) {
|
||||||
/* /databases/id/items/id.mp3 */
|
/* /databases/id/items/id.mp3 */
|
||||||
dispatch_stream(pwsc,pqi);
|
dispatch_stream(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||||
(!strcasecmp(pqi->uri_sections[3],"add"))) {
|
(!strcasecmp(pqi->uri_sections[3],"add"))) {
|
||||||
/* /databases/id/containers/add */
|
/* /databases/id/containers/add */
|
||||||
dispatch_addplaylist(pwsc,pqi);
|
dispatch_addplaylist(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||||
(!strcasecmp(pqi->uri_sections[3],"del"))) {
|
(!strcasecmp(pqi->uri_sections[3],"del"))) {
|
||||||
/* /databases/id/containers/del */
|
/* /databases/id/containers/del */
|
||||||
dispatch_deleteplaylist(pwsc,pqi);
|
dispatch_deleteplaylist(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||||
(!strcasecmp(pqi->uri_sections[3],"edit"))) {
|
(!strcasecmp(pqi->uri_sections[3],"edit"))) {
|
||||||
/* /databases/id/contaienrs/edit */
|
/* /databases/id/contaienrs/edit */
|
||||||
dispatch_editplaylist(pwsc,pqi);
|
dispatch_editplaylist(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pwsc->close=1;
|
pwsc->close=1;
|
||||||
free(pqi);
|
dispatch_cleanup(pqi);
|
||||||
ws_returnerror(pwsc,404,"Page not found");
|
ws_returnerror(pwsc,404,"Page not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -288,6 +305,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
(!strcasecmp(pqi->uri_sections[4],"items"))) {
|
(!strcasecmp(pqi->uri_sections[4],"items"))) {
|
||||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||||
dispatch_playlistitems(pwsc,pqi);
|
dispatch_playlistitems(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
if((!strcasecmp(pqi->uri_sections[2],"containers")) &&
|
||||||
@ -295,6 +313,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
/* /databases/id/containers/id/del */
|
/* /databases/id/containers/id/del */
|
||||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||||
dispatch_deleteplaylistitems(pwsc,pqi);
|
dispatch_deleteplaylistitems(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,13 +323,14 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
|||||||
(!strcasecmp(pqi->uri_sections[5],"add"))) {
|
(!strcasecmp(pqi->uri_sections[5],"add"))) {
|
||||||
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
pqi->playlist_id=atoi(pqi->uri_sections[3]);
|
||||||
dispatch_addplaylistitems(pwsc,pqi);
|
dispatch_addplaylistitems(pwsc,pqi);
|
||||||
|
dispatch_cleanup(pqi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pwsc->close=1;
|
pwsc->close=1;
|
||||||
free(pqi);
|
dispatch_cleanup(pqi);
|
||||||
ws_returnerror(pwsc,404,"Page not found");
|
ws_returnerror(pwsc,404,"Page not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,9 @@ void scan_process_playlistlist(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(strcasecmp(ext,".xml") == 0) {
|
if(strcasecmp(ext,".xml") == 0) {
|
||||||
scan_xml_playlist(pnext->path);
|
if(conf_get_int("scanning","process xml",1)) {
|
||||||
|
scan_xml_playlist(pnext->path);
|
||||||
|
}
|
||||||
} else if(strcasecmp(ext,".m3u") == 0) {
|
} else if(strcasecmp(ext,".m3u") == 0) {
|
||||||
scan_static_playlist(pnext->path);
|
scan_static_playlist(pnext->path);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
* Test harness for the parser
|
* Test harness for the parser
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "conf.h"
|
||||||
|
#include "db-generic.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "smart-parser.h"
|
#include "smart-parser.h"
|
||||||
|
|
||||||
@ -19,9 +22,18 @@ int main(int argc, char *argv[]) {
|
|||||||
int option;
|
int option;
|
||||||
int type=0;
|
int type=0;
|
||||||
PARSETREE pt;
|
PARSETREE pt;
|
||||||
|
char *configfile = "/etc/mt-daapd.conf";
|
||||||
while((option = getopt(argc, argv, "d:t:")) != -1) {
|
char db_type[40];
|
||||||
|
char db_parms[PATH_MAX];
|
||||||
|
int size;
|
||||||
|
int err;
|
||||||
|
char *perr;
|
||||||
|
|
||||||
|
while((option = getopt(argc, argv, "d:t:c:")) != -1) {
|
||||||
switch(option) {
|
switch(option) {
|
||||||
|
case 'c':
|
||||||
|
configfile = optarg;
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
err_setlevel(atoi(optarg));
|
err_setlevel(atoi(optarg));
|
||||||
break;
|
break;
|
||||||
@ -34,6 +46,22 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(conf_read(configfile) != CONF_E_SUCCESS) {
|
||||||
|
fprintf(stderr,"could not read config file: %s\n",configfile);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(db_type);
|
||||||
|
conf_get_string("general","db_type","sqlite",db_type,&size);
|
||||||
|
size = sizeof(db_parms);
|
||||||
|
conf_get_string("general","db_parms","/var/cache/mt-daapd",db_parms,&size);
|
||||||
|
|
||||||
|
err=db_open(&perr,db_type,db_parms);
|
||||||
|
if(err != DB_E_SUCCESS) {
|
||||||
|
fprintf(stderr,"Error opening db: %s\n",perr);
|
||||||
|
free(perr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Parsing %s\n",argv[optind]);
|
printf("Parsing %s\n",argv[optind]);
|
||||||
|
|
||||||
@ -45,6 +73,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sp_dispose(pt);
|
sp_dispose(pt);
|
||||||
|
conf_close();
|
||||||
|
|
||||||
printf("Done!\n");
|
printf("Done!\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS := $(CFLAGS) -g -I/sw/include -DHAVE_CONFIG_H -I. -I.. -Wall -DERR_LEAN
|
CFLAGS := $(CFLAGS) -g -I/opt/local/include -DHAVE_CONFIG_H -I. -I.. -Wall -DERR_LEAN -DHAVE_SQL
|
||||||
|
LDFLAGS := $(LDFLAGS) -L/opt/local/lib -lsqlite -lsqlite3
|
||||||
TARGET=parser
|
TARGET=parser
|
||||||
OBJECTS=parser-driver.o smart-parser.o err.o
|
OBJECTS=parser-driver.o smart-parser.o err.o db-sql.o db-generic.o ssc.o db-sql-sqlite3.o db-sql-sqlite2.o conf.o ll.o
|
||||||
|
|
||||||
$(TARGET): $(OBJECTS)
|
$(TARGET): $(OBJECTS)
|
||||||
$(CC) -o $(TARGET) $(LDFLAGS) $(OBJECTS)
|
$(CC) -o $(TARGET) $(LDFLAGS) $(OBJECTS)
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
|
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SQL
|
||||||
|
extern int db_sql_escape(char *buffer, int *size, char *fmt, ...);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct tag_token {
|
typedef struct tag_token {
|
||||||
int token_id;
|
int token_id;
|
||||||
union {
|
union {
|
||||||
@ -197,7 +202,7 @@ typedef struct tag_fieldlookup {
|
|||||||
/* normal terminators, in-string terminators, escapes, quotes */
|
/* normal terminators, in-string terminators, escapes, quotes */
|
||||||
char *sp_terminators[2][4] = {
|
char *sp_terminators[2][4] = {
|
||||||
{ " \t\n\r\"<>=()|&!", "\"","\"","\"" },
|
{ " \t\n\r\"<>=()|&!", "\"","\"","\"" },
|
||||||
{ "()'+: -,", "')", "\\*'","" }
|
{ "()'+: -,", "'", "\\*'","" }
|
||||||
};
|
};
|
||||||
|
|
||||||
FIELDLOOKUP sp_symbols_0[] = {
|
FIELDLOOKUP sp_symbols_0[] = {
|
||||||
@ -465,6 +470,7 @@ int sp_scan(PARSETREE tree, int hint) {
|
|||||||
time_t tval;
|
time_t tval;
|
||||||
char *qstr;
|
char *qstr;
|
||||||
char *token_string;
|
char *token_string;
|
||||||
|
char *dst, *src;
|
||||||
|
|
||||||
if(tree->token.token_id & 0x2000) {
|
if(tree->token.token_id & 0x2000) {
|
||||||
if(tree->token.data.cvalue)
|
if(tree->token.data.cvalue)
|
||||||
@ -544,8 +550,10 @@ int sp_scan(PARSETREE tree, int hint) {
|
|||||||
/* walk to a terminator */
|
/* walk to a terminator */
|
||||||
tail = tree->current;
|
tail = tree->current;
|
||||||
|
|
||||||
/* FIXME: escaped characters */
|
|
||||||
while((*tail) && (!strchr(terminator,*tail))) {
|
while((*tail) && (!strchr(terminator,*tail))) {
|
||||||
|
/* skip escaped characters -- will be unescaped later */
|
||||||
|
if((*tail == '\\')&&(*(tail+1) != '\0'))
|
||||||
|
tail++;
|
||||||
tail++;
|
tail++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +642,19 @@ int sp_scan(PARSETREE tree, int hint) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* escape string */
|
||||||
|
if(tree->token.token_id == T_STRING) {
|
||||||
|
src = dst = tree->token.data.cvalue;
|
||||||
|
while(*src) {
|
||||||
|
if(*src != '\\') {
|
||||||
|
*dst++ = *src++;
|
||||||
|
} else {
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
|
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
|
||||||
tree->token.token_id);
|
tree->token.token_id);
|
||||||
if(tree->token.token_id & 0x2000)
|
if(tree->token.token_id & 0x2000)
|
||||||
@ -1304,6 +1325,7 @@ int sp_dispose(PARSETREE tree) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SQL
|
||||||
/**
|
/**
|
||||||
* calculate the size required to render the tree as a
|
* calculate the size required to render the tree as a
|
||||||
* sql query.
|
* sql query.
|
||||||
@ -1313,6 +1335,7 @@ int sp_dispose(PARSETREE tree) {
|
|||||||
*/
|
*/
|
||||||
int sp_node_size(SP_NODE *node) {
|
int sp_node_size(SP_NODE *node) {
|
||||||
int size;
|
int size;
|
||||||
|
int string_size;
|
||||||
|
|
||||||
if(node->op_type == SP_OPTYPE_ANDOR) {
|
if(node->op_type == SP_OPTYPE_ANDOR) {
|
||||||
size = sp_node_size(node->left.node);
|
size = sp_node_size(node->left.node);
|
||||||
@ -1329,7 +1352,9 @@ int sp_node_size(SP_NODE *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(node->op_type == SP_OPTYPE_STRING) {
|
if(node->op_type == SP_OPTYPE_STRING) {
|
||||||
size += (2 + (int) strlen(node->right.cvalue));
|
string_size = 0;
|
||||||
|
db_sql_escape(NULL,&string_size,"%q",node->right.cvalue);
|
||||||
|
size += (2 + string_size);
|
||||||
if(node->op == T_INCLUDES) {
|
if(node->op == T_INCLUDES) {
|
||||||
size += 2; /* extra %'s */
|
size += 2; /* extra %'s */
|
||||||
}
|
}
|
||||||
@ -1358,6 +1383,7 @@ int sp_node_size(SP_NODE *node) {
|
|||||||
*/
|
*/
|
||||||
void sp_serialize_sql(SP_NODE *node, char *string) {
|
void sp_serialize_sql(SP_NODE *node, char *string) {
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
|
int size;
|
||||||
|
|
||||||
if(node->op_type == SP_OPTYPE_ANDOR) {
|
if(node->op_type == SP_OPTYPE_ANDOR) {
|
||||||
strcat(string,"(");
|
strcat(string,"(");
|
||||||
@ -1379,7 +1405,15 @@ void sp_serialize_sql(SP_NODE *node, char *string) {
|
|||||||
strcat(string,"'");
|
strcat(string,"'");
|
||||||
if((node->op == T_INCLUDES) || (node->op == T_ENDSWITH))
|
if((node->op == T_INCLUDES) || (node->op == T_ENDSWITH))
|
||||||
strcat(string,"%");
|
strcat(string,"%");
|
||||||
strcat(string,node->right.cvalue);
|
size = 0;
|
||||||
|
db_sql_escape(NULL,&size,"%q",node->right.cvalue);
|
||||||
|
|
||||||
|
/* we don't have a way to verify we have that much
|
||||||
|
* room, but we must... we allocated it earlier.
|
||||||
|
*/
|
||||||
|
db_sql_escape(&string[strlen(string)],&size,"%q",node->right.cvalue);
|
||||||
|
|
||||||
|
// strcat(string,node->right.cvalue);
|
||||||
if((node->op == T_INCLUDES) || (node->op == T_STARTSWITH))
|
if((node->op == T_INCLUDES) || (node->op == T_STARTSWITH))
|
||||||
strcat(string,"%");
|
strcat(string,"%");
|
||||||
strcat(string,"'");
|
strcat(string,"'");
|
||||||
@ -1411,15 +1445,20 @@ char *sp_sql_clause(PARSETREE tree) {
|
|||||||
int size;
|
int size;
|
||||||
char *sql;
|
char *sql;
|
||||||
|
|
||||||
|
DPRINTF(E_DBG,L_PARSE,"Fetching sql statement size\n");
|
||||||
size = sp_node_size(tree->tree);
|
size = sp_node_size(tree->tree);
|
||||||
|
DPRINTF(E_DBG,L_PARSE,"Size: %d\n",size);
|
||||||
|
|
||||||
sql = (char*)malloc(size+1);
|
sql = (char*)malloc(size+1);
|
||||||
|
|
||||||
memset(sql,0x00,size+1);
|
memset(sql,0x00,size+1);
|
||||||
sp_serialize_sql(tree->tree,sql);
|
sp_serialize_sql(tree->tree,sql);
|
||||||
|
|
||||||
|
DPRINTF(E_DBG,L_PARSE,"Serialized to : %s\n",sql);
|
||||||
|
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_SQL */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
typedef void* PARSETREE;
|
typedef void* PARSETREE;
|
||||||
|
|
||||||
extern PARSETREE sp_init(void);
|
extern PARSETREE sp_init(void);
|
||||||
extern int sp_parse(PARSETREE *tree, char *term, int type);
|
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user