* Some SQL optimizations. Noticeable mostly on very slow systems with very large media libraries.
* Add basic DLNA/UPnP-AV SortCriteria support.
This commit is contained in:
parent
11b208a6e6
commit
226cf8bb66
@ -461,7 +461,7 @@ insert_directory(const char * name, const char * path, const char * base, const
|
|||||||
{
|
{
|
||||||
if( strcmp(id_buf, last_found) == 0 )
|
if( strcmp(id_buf, last_found) == 0 )
|
||||||
break;
|
break;
|
||||||
sql = sqlite3_mprintf("SELECT count(OBJECT_ID) from OBJECTS where OBJECT_ID = '%s'", id_buf);
|
sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf);
|
||||||
if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) )
|
if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) )
|
||||||
{
|
{
|
||||||
sqlite3_free_table(result);
|
sqlite3_free_table(result);
|
||||||
|
@ -554,11 +554,10 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite
|
|||||||
args.start = itemStart+anchorOffset;
|
args.start = itemStart+anchorOffset;
|
||||||
sqlite3Prng.isInit = 0;
|
sqlite3Prng.isInit = 0;
|
||||||
|
|
||||||
asprintf(&sql, "SELECT count(*) from "
|
asprintf(&sql, "SELECT count(distinct DETAIL_ID) "
|
||||||
"( select 1 from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
|
"from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
|
||||||
" where %s and (%s)"
|
" where %s and (%s)",
|
||||||
" %s )",
|
which, myfilter);
|
||||||
which, myfilter, groupBy);
|
|
||||||
DPRINTF(E_DEBUG, L_TIVO, "Count SQL: %s\n", sql);
|
DPRINTF(E_DEBUG, L_TIVO, "Count SQL: %s\n", sql);
|
||||||
ret = sql_get_table(db, sql, &result, NULL, NULL);
|
ret = sql_get_table(db, sql, &result, NULL, NULL);
|
||||||
if( ret == SQLITE_OK )
|
if( ret == SQLITE_OK )
|
||||||
|
177
upnpsoap.c
177
upnpsoap.c
@ -127,7 +127,12 @@ GetSortCapabilities(struct upnphttp * h, const char * action)
|
|||||||
static const char resp[] =
|
static const char resp[] =
|
||||||
"<u:%sResponse "
|
"<u:%sResponse "
|
||||||
"xmlns:u=\"%s\">"
|
"xmlns:u=\"%s\">"
|
||||||
"<SortCaps></SortCaps>"
|
"<SortCaps>"
|
||||||
|
"dc:title,"
|
||||||
|
"dc:date,"
|
||||||
|
"upnp:class,"
|
||||||
|
"upnp:originalTrackNumber"
|
||||||
|
"</SortCaps>"
|
||||||
"</u:%sResponse>";
|
"</u:%sResponse>";
|
||||||
|
|
||||||
char body[512];
|
char body[512];
|
||||||
@ -275,6 +280,81 @@ set_filter_flags(char * filter)
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
parse_sort_criteria(char * sortCriteria)
|
||||||
|
{
|
||||||
|
char *order = NULL;
|
||||||
|
char *item, *saveptr;
|
||||||
|
int i, ret, reverse, title_sorted = 0;
|
||||||
|
|
||||||
|
if( !sortCriteria )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if( (item = strtok_r(sortCriteria, ",", &saveptr)) )
|
||||||
|
{
|
||||||
|
order = malloc(4096);
|
||||||
|
strcpy(order, "order by ");
|
||||||
|
}
|
||||||
|
for( i=0; item != NULL; i++ )
|
||||||
|
{
|
||||||
|
reverse=0;
|
||||||
|
if( i )
|
||||||
|
strcat(order, ", ");
|
||||||
|
if( *item == '+' )
|
||||||
|
{
|
||||||
|
item++;
|
||||||
|
}
|
||||||
|
else if( *item == '-' )
|
||||||
|
{
|
||||||
|
reverse = 1;
|
||||||
|
item++;
|
||||||
|
}
|
||||||
|
if( strcasecmp(item, "upnp:class") == 0 )
|
||||||
|
{
|
||||||
|
strcat(order, "o.CLASS");
|
||||||
|
}
|
||||||
|
else if( strcasecmp(item, "dc:title") == 0 )
|
||||||
|
{
|
||||||
|
strcat(order, "d.TITLE");
|
||||||
|
title_sorted = 1;
|
||||||
|
}
|
||||||
|
else if( strcasecmp(item, "dc:date") == 0 )
|
||||||
|
{
|
||||||
|
strcat(order, "d.DATE");
|
||||||
|
}
|
||||||
|
else if( strcasecmp(item, "upnp:originalTrackNumber") == 0 )
|
||||||
|
{
|
||||||
|
strcat(order, "d.TRACK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Unhandled SortCriteria [%s]\n", item);
|
||||||
|
if( i )
|
||||||
|
{
|
||||||
|
ret = strlen(order);
|
||||||
|
order[ret-2] = '\0';
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
goto unhandled_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( reverse )
|
||||||
|
strcat(order, " DESC");
|
||||||
|
unhandled_order:
|
||||||
|
item = strtok_r(NULL, ",", &saveptr);
|
||||||
|
}
|
||||||
|
if( i <= 0 )
|
||||||
|
{
|
||||||
|
free(order);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Add a "tiebreaker" sort order */
|
||||||
|
if( !title_sorted )
|
||||||
|
strcat(order, ", TITLE ASC");
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, o.DETAIL_ID, o.CLASS," \
|
#define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, o.DETAIL_ID, o.CLASS," \
|
||||||
" d.SIZE, d.TITLE, d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST," \
|
" d.SIZE, d.TITLE, d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST," \
|
||||||
" d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, d.TRACK, d.DATE, d.RESOLUTION," \
|
" d.ALBUM, d.GENRE, d.COMMENT, d.CHANNELS, d.TRACK, d.DATE, d.RESOLUTION," \
|
||||||
@ -294,10 +374,6 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
int children, ret = 0;
|
int children, ret = 0;
|
||||||
static int warned = 0;
|
static int warned = 0;
|
||||||
|
|
||||||
passed_args->total++;
|
|
||||||
|
|
||||||
if( passed_args->requested && (passed_args->returned >= passed_args->requested) )
|
|
||||||
return 0;
|
|
||||||
/* Make sure we have at least 4KB left of allocated memory to finish the response. */
|
/* Make sure we have at least 4KB left of allocated memory to finish the response. */
|
||||||
if( passed_args->size > 1044480 && !warned )
|
if( passed_args->size > 1044480 && !warned )
|
||||||
{
|
{
|
||||||
@ -459,7 +535,7 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
passed_args->size += ret;
|
passed_args->size += ret;
|
||||||
if( passed_args->filter & FILTER_CHILDCOUNT )
|
if( passed_args->filter & FILTER_CHILDCOUNT )
|
||||||
{
|
{
|
||||||
sprintf(str_buf, "SELECT count(ID) from OBJECTS where PARENT_ID = '%s';", id);
|
sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id);
|
||||||
ret = sql_get_table(db, str_buf, &result, NULL, NULL);
|
ret = sql_get_table(db, str_buf, &result, NULL, NULL);
|
||||||
if( ret == SQLITE_OK ) {
|
if( ret == SQLITE_OK ) {
|
||||||
children = atoi(result[1]);
|
children = atoi(result[1]);
|
||||||
@ -542,8 +618,10 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
char str_buf[512];
|
char str_buf[512];
|
||||||
char *zErrMsg = 0;
|
char *zErrMsg = 0;
|
||||||
char *sql;
|
char *sql;
|
||||||
|
char **result;
|
||||||
int ret;
|
int ret;
|
||||||
struct Response args;
|
struct Response args;
|
||||||
|
int totalMatches = 0;
|
||||||
struct NameValueParserData data;
|
struct NameValueParserData data;
|
||||||
*resp = '\0';
|
*resp = '\0';
|
||||||
|
|
||||||
@ -554,10 +632,19 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
char * Filter = GetValueFromNameValueList(&data, "Filter");
|
char * Filter = GetValueFromNameValueList(&data, "Filter");
|
||||||
char * BrowseFlag = GetValueFromNameValueList(&data, "BrowseFlag");
|
char * BrowseFlag = GetValueFromNameValueList(&data, "BrowseFlag");
|
||||||
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
||||||
|
char * orderBy = NULL;
|
||||||
if( !ObjectId )
|
if( !ObjectId )
|
||||||
ObjectId = GetValueFromNameValueList(&data, "ContainerID");
|
ObjectId = GetValueFromNameValueList(&data, "ContainerID");
|
||||||
memset(&args, 0, sizeof(args));
|
memset(&args, 0, sizeof(args));
|
||||||
|
|
||||||
|
if( !RequestedCount )
|
||||||
|
RequestedCount = -1;
|
||||||
|
#ifdef __sparc__ /* Sorting takes too long on slow processors with very large containers */
|
||||||
|
if( totalMatches < 10000 )
|
||||||
|
#endif
|
||||||
|
orderBy = parse_sort_criteria(SortCriteria);
|
||||||
|
|
||||||
|
|
||||||
args.resp = resp;
|
args.resp = resp;
|
||||||
args.size = sprintf(resp, "%s", resp0);
|
args.size = sprintf(resp, "%s", resp0);
|
||||||
/* See if we need to include DLNA namespace reference */
|
/* See if we need to include DLNA namespace reference */
|
||||||
@ -572,7 +659,6 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
memcpy(resp+args.size, &str_buf, ret+1);
|
memcpy(resp+args.size, &str_buf, ret+1);
|
||||||
args.size += ret;
|
args.size += ret;
|
||||||
|
|
||||||
args.total = StartingIndex;
|
|
||||||
args.returned = 0;
|
args.returned = 0;
|
||||||
args.requested = RequestedCount;
|
args.requested = RequestedCount;
|
||||||
args.client = h->req_client;
|
args.client = h->req_client;
|
||||||
@ -603,14 +689,23 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
" where OBJECT_ID = '%s';"
|
" where OBJECT_ID = '%s';"
|
||||||
, ObjectId);
|
, ObjectId);
|
||||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||||
|
totalMatches = args.returned;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId);
|
||||||
|
ret = sql_get_table(db, str_buf, &result, NULL, NULL);
|
||||||
|
if( ret == SQLITE_OK ) {
|
||||||
|
totalMatches = atoi(result[1]);
|
||||||
|
sqlite3_free_table(result);
|
||||||
|
}
|
||||||
sql = sqlite3_mprintf( SELECT_COLUMNS
|
sql = sqlite3_mprintf( SELECT_COLUMNS
|
||||||
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||||
" where PARENT_ID = '%s' order by d.TRACK, d.ARTIST, d.TITLE limit %d, -1;",
|
" where PARENT_ID = '%s' %s limit %d, %d;",
|
||||||
ObjectId, StartingIndex);
|
ObjectId, orderBy, StartingIndex, RequestedCount);
|
||||||
|
DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql);
|
||||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||||
|
totalMatches = args.returned;
|
||||||
}
|
}
|
||||||
sqlite3_free(sql);
|
sqlite3_free(sql);
|
||||||
if( ret != SQLITE_OK )
|
if( ret != SQLITE_OK )
|
||||||
@ -623,11 +718,13 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
"<TotalMatches>%u</TotalMatches>\n"
|
"<TotalMatches>%u</TotalMatches>\n"
|
||||||
"<UpdateID>%u</UpdateID>"
|
"<UpdateID>%u</UpdateID>"
|
||||||
"</u:BrowseResponse>",
|
"</u:BrowseResponse>",
|
||||||
args.returned, args.total, updateID);
|
args.returned, totalMatches, updateID);
|
||||||
memcpy(resp+args.size, &str_buf, ret+1);
|
memcpy(resp+args.size, &str_buf, ret+1);
|
||||||
args.size += ret;
|
args.size += ret;
|
||||||
BuildSendAndCloseSoapResp(h, resp, args.size);
|
BuildSendAndCloseSoapResp(h, resp, args.size);
|
||||||
ClearNameValueList(&data);
|
ClearNameValueList(&data);
|
||||||
|
if( orderBy )
|
||||||
|
free(orderBy);
|
||||||
free(resp);
|
free(resp);
|
||||||
if( h->req_client == EXbox )
|
if( h->req_client == EXbox )
|
||||||
{
|
{
|
||||||
@ -648,9 +745,11 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
char *resp = malloc(1048576);
|
char *resp = malloc(1048576);
|
||||||
char *zErrMsg = 0;
|
char *zErrMsg = 0;
|
||||||
char *sql;
|
char *sql;
|
||||||
|
char **result;
|
||||||
char str_buf[4096];
|
char str_buf[4096];
|
||||||
int ret;
|
int ret;
|
||||||
struct Response args;
|
struct Response args;
|
||||||
|
int totalMatches = 0;
|
||||||
*resp = '\0';
|
*resp = '\0';
|
||||||
|
|
||||||
struct NameValueParserData data;
|
struct NameValueParserData data;
|
||||||
@ -662,9 +761,17 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
char * SearchCriteria = GetValueFromNameValueList(&data, "SearchCriteria");
|
char * SearchCriteria = GetValueFromNameValueList(&data, "SearchCriteria");
|
||||||
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
||||||
char * newSearchCriteria = NULL;
|
char * newSearchCriteria = NULL;
|
||||||
|
char * orderBy = NULL;
|
||||||
|
char groupBy[] = "group by DETAIL_ID";
|
||||||
memset(&args, 0, sizeof(args));
|
memset(&args, 0, sizeof(args));
|
||||||
|
|
||||||
|
if( !RequestedCount )
|
||||||
|
RequestedCount = -1;
|
||||||
|
#ifdef __sparc__ /* Sorting takes too long on slow processors with very large containers */
|
||||||
|
if( totalMatches < 10000 )
|
||||||
|
#endif
|
||||||
|
orderBy = parse_sort_criteria(SortCriteria);
|
||||||
|
|
||||||
args.resp = resp;
|
args.resp = resp;
|
||||||
args.size = sprintf(resp, "%s", resp0);
|
args.size = sprintf(resp, "%s", resp0);
|
||||||
/* See if we need to include DLNA namespace reference */
|
/* See if we need to include DLNA namespace reference */
|
||||||
@ -679,7 +786,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
memcpy(resp+args.size, &str_buf, ret+1);
|
memcpy(resp+args.size, &str_buf, ret+1);
|
||||||
args.size += ret;
|
args.size += ret;
|
||||||
|
|
||||||
args.total = StartingIndex;
|
|
||||||
args.returned = 0;
|
args.returned = 0;
|
||||||
args.requested = RequestedCount;
|
args.requested = RequestedCount;
|
||||||
args.client = h->req_client;
|
args.client = h->req_client;
|
||||||
@ -695,6 +801,20 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
ContainerID = strdup("1$7");
|
ContainerID = strdup("1$7");
|
||||||
else
|
else
|
||||||
ContainerID = strdup(ContainerID);
|
ContainerID = strdup(ContainerID);
|
||||||
|
#if 0 // Looks like the 360 already does this
|
||||||
|
/* Sort by track number for some containers */
|
||||||
|
if( orderBy &&
|
||||||
|
((strncmp(ContainerID, "1$5", 3) == 0) ||
|
||||||
|
(strncmp(ContainerID, "1$6", 3) == 0) ||
|
||||||
|
(strncmp(ContainerID, "1$7", 3) == 0)) )
|
||||||
|
{
|
||||||
|
DPRINTF(E_DEBUG, L_HTTP, "Old sort order: %s\n", orderBy);
|
||||||
|
sprintf(str_buf, "d.TRACK, ");
|
||||||
|
memmove(orderBy+18, orderBy+9, strlen(orderBy)+1);
|
||||||
|
memmove(orderBy+9, &str_buf, 9);
|
||||||
|
DPRINTF(E_DEBUG, L_HTTP, "New sort order: %s\n", orderBy);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "Browsing ContentDirectory:\n"
|
DPRINTF(E_DEBUG, L_HTTP, "Browsing ContentDirectory:\n"
|
||||||
" * ObjectID: %s\n"
|
" * ObjectID: %s\n"
|
||||||
@ -708,6 +828,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
|
|
||||||
if( strcmp(ContainerID, "0") == 0 )
|
if( strcmp(ContainerID, "0") == 0 )
|
||||||
*ContainerID = '*';
|
*ContainerID = '*';
|
||||||
|
else if( strcmp(ContainerID, "1$4") == 0 )
|
||||||
|
groupBy[0] = '\0';
|
||||||
if( !SearchCriteria )
|
if( !SearchCriteria )
|
||||||
{
|
{
|
||||||
asprintf(&newSearchCriteria, "1 = 1");
|
asprintf(&newSearchCriteria, "1 = 1");
|
||||||
@ -717,8 +839,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
{
|
{
|
||||||
SearchCriteria = modifyString(SearchCriteria, """, "\"", 0);
|
SearchCriteria = modifyString(SearchCriteria, """, "\"", 0);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "'", "'", 0);
|
SearchCriteria = modifyString(SearchCriteria, "'", "'", 0);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "derivedfrom", "like", 1);
|
SearchCriteria = modifyString(SearchCriteria, "derivedfrom", "glob", 1);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "contains", "like", 1);
|
SearchCriteria = modifyString(SearchCriteria, "contains", "glob", 1);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "dc:title", "d.TITLE", 0);
|
SearchCriteria = modifyString(SearchCriteria, "dc:title", "d.TITLE", 0);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "dc:creator", "d.CREATOR", 0);
|
SearchCriteria = modifyString(SearchCriteria, "dc:creator", "d.CREATOR", 0);
|
||||||
SearchCriteria = modifyString(SearchCriteria, "upnp:class", "o.CLASS", 0);
|
SearchCriteria = modifyString(SearchCriteria, "upnp:class", "o.CLASS", 0);
|
||||||
@ -738,17 +860,30 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
}
|
}
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "Translated SearchCriteria: %s\n", SearchCriteria);
|
DPRINTF(E_DEBUG, L_HTTP, "Translated SearchCriteria: %s\n", SearchCriteria);
|
||||||
|
|
||||||
|
sprintf(str_buf, "SELECT (select count(distinct DETAIL_ID) from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
|
||||||
|
" where (OBJECT_ID glob '%s$*') and (%s))"
|
||||||
|
" + "
|
||||||
|
"(select count(*) from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
|
||||||
|
" where (OBJECT_ID = '%s') and (%s))",
|
||||||
|
ContainerID, SearchCriteria, ContainerID, SearchCriteria);
|
||||||
|
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Count SQL: %s\n", sql);
|
||||||
|
ret = sql_get_table(db, str_buf, &result, NULL, NULL);
|
||||||
|
if( ret == SQLITE_OK ) {
|
||||||
|
totalMatches = atoi(result[1]);
|
||||||
|
sqlite3_free_table(result);
|
||||||
|
}
|
||||||
|
|
||||||
sql = sqlite3_mprintf( SELECT_COLUMNS
|
sql = sqlite3_mprintf( SELECT_COLUMNS
|
||||||
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||||
" where OBJECT_ID glob '%s$*' and (%s) group by DETAIL_ID "
|
" where OBJECT_ID glob '%s$*' and (%s) %s "
|
||||||
"%z"
|
"%z %s"
|
||||||
" order by d.TRACK, d.TITLE limit %d, -1;",
|
" limit %d, %d",
|
||||||
ContainerID, SearchCriteria,
|
ContainerID, SearchCriteria, groupBy,
|
||||||
(*ContainerID == '*') ? NULL :
|
(*ContainerID == '*') ? NULL :
|
||||||
sqlite3_mprintf("UNION ALL " SELECT_COLUMNS
|
sqlite3_mprintf("UNION ALL " SELECT_COLUMNS
|
||||||
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
"from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||||
" where OBJECT_ID = '%s' and (%s) ", ContainerID, SearchCriteria),
|
" where OBJECT_ID = '%s' and (%s) ", ContainerID, SearchCriteria),
|
||||||
StartingIndex);
|
orderBy, StartingIndex, RequestedCount);
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "Search SQL: %s\n", sql);
|
DPRINTF(E_DEBUG, L_HTTP, "Search SQL: %s\n", sql);
|
||||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||||
if( ret != SQLITE_OK )
|
if( ret != SQLITE_OK )
|
||||||
@ -763,11 +898,13 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
"<TotalMatches>%u</TotalMatches>\n"
|
"<TotalMatches>%u</TotalMatches>\n"
|
||||||
"<UpdateID>%u</UpdateID>"
|
"<UpdateID>%u</UpdateID>"
|
||||||
"</u:SearchResponse>",
|
"</u:SearchResponse>",
|
||||||
args.returned, args.total, updateID);
|
args.returned, totalMatches, updateID);
|
||||||
memcpy(resp+args.size, &str_buf, ret+1);
|
memcpy(resp+args.size, &str_buf, ret+1);
|
||||||
args.size += ret;
|
args.size += ret;
|
||||||
BuildSendAndCloseSoapResp(h, resp, args.size);
|
BuildSendAndCloseSoapResp(h, resp, args.size);
|
||||||
ClearNameValueList(&data);
|
ClearNameValueList(&data);
|
||||||
|
if( orderBy )
|
||||||
|
free(orderBy);
|
||||||
if( newSearchCriteria )
|
if( newSearchCriteria )
|
||||||
free(newSearchCriteria);
|
free(newSearchCriteria);
|
||||||
free(resp);
|
free(resp);
|
||||||
|
@ -20,7 +20,6 @@ struct Response
|
|||||||
int start;
|
int start;
|
||||||
int returned;
|
int returned;
|
||||||
int requested;
|
int requested;
|
||||||
int total;
|
|
||||||
int size;
|
int size;
|
||||||
u_int32_t filter;
|
u_int32_t filter;
|
||||||
enum clientType client;
|
enum clientType client;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user