62 #ifdef HAVE_SYS_STAT_H
66 #define TABLE_FILES "musicindexfiles"
67 #define TABLE_DIRS "musicindexdirs"
68 #define TABLE_FORMAT "musicindexformat"
69 #define TABLE_FORMAT_ID 1
70 #define SQL_SMAX_UPD 64
71 #define SQL_SMAX_H 256
72 #define SUBSTRINGIFY(x) STRINGIFY(x)
73 #define STRINGIFY(x) #x
75 #define AINC_OVFLERR 1062
89 #define SQL_CDATAF "cvers,mtime,filetype,flags,track,posn," \
90 "date,freq,length,bitrate,size," \
91 "album,artist,title,genre"
115 p->
mtime = (unsigned)atol(mysql_row[1]);
116 p->
filetype = (
signed char)atoi(mysql_row[2]);
117 p->
flags = (
unsigned char)atoi(mysql_row[3]);
118 p->
track = (
unsigned char)atoi(mysql_row[4]);
119 p->
posn = (
unsigned char)atoi(mysql_row[5]);
120 p->
date = (
unsigned short)atoi(mysql_row[6]);
121 p->
freq = (
unsigned short)atoi(mysql_row[7]);
122 p->
length = (
unsigned short)atoi(mysql_row[8]);
123 p->
bitrate = (unsigned)atol(mysql_row[9]);
124 p->
size = (unsigned)atol(mysql_row[10]);
154 MYSQL_RES *mysql_res = NULL;
156 unsigned short len, create_dirs = 1, create_files = 1, create_format = 1;
161 const char const drop_tformat[] =
"DROP TABLE IF EXISTS `" TABLE_FORMAT "`";
162 const char const create_tformat[] =
"CREATE TABLE `" TABLE_FORMAT "` ("
164 const char const init_tformat[] =
"INSERT INTO `" TABLE_FORMAT "` () VALUES ()";
166 const char const drop_tdirs[] =
"DROP TABLE IF EXISTS `" TABLE_DIRS "`";
167 const char const create_tdirs[] =
"CREATE TABLE `" TABLE_DIRS "` ("
168 "`id` SMALLINT UNSIGNED SERIAL DEFAULT VALUE,"
169 "`timestamp` INT UNSIGNED,"
170 #if MYSQL_VERSION_ID > 50003
172 "INDEX `check` (`fullpath`))"
174 "`fullpath` TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,"
176 "CHARACTER SET = utf8,"
177 "COLLATE = utf8_bin";
182 const char const drop_tfiles[] =
"DROP TABLE IF EXISTS `" TABLE_FILES "`";
183 const char const create_tfiles[] =
"CREATE TABLE `" TABLE_FILES "` ("
184 "`id` MEDIUMINT UNSIGNED SERIAL DEFAULT VALUE,"
185 "`pid` SMALLINT UNSIGNED NOT NULL REFERENCES `" TABLE_DIRS "`(`id`),"
186 "`filetype` TINYINT NOT NULL,"
187 "`flags` TINYINT UNSIGNED NOT NULL,"
188 "`track` TINYINT UNSIGNED NOT NULL,"
189 "`posn` TINYINT UNSIGNED NOT NULL,"
190 "`cvers` TINYINT UNSIGNED NOT NULL,"
191 "`date` SMALLINT UNSIGNED NOT NULL,"
192 "`freq` SMALLINT UNSIGNED NOT NULL,"
193 "`length` SMALLINT UNSIGNED NOT NULL,"
194 "`bitrate` MEDIUMINT UNSIGNED NOT NULL,"
195 "`size` INT UNSIGNED NOT NULL,"
196 "`mtime` INT UNSIGNED NOT NULL,"
198 "`album` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci,"
199 "`artist` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci,"
200 "`title` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,"
201 "`filename` VARCHAR(" SUBSTRINGIFY(
MAX_FNAME)
") CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,"
202 "INDEX `make_entry` (`pid`,`filename`),"
203 "FULLTEXT INDEX `search` (`filename`,`title`,`artist`,`album`))"
204 "CHARACTER SET = utf8,"
205 "COLLATE = utf8_bin";
221 temp = strchr(setup_string,
':');
225 len = strchr(setup_string,
'@') - (temp+1);
233 len = temp - (setup_string);
240 len = strchr(setup_string,
'@') - (setup_string);
251 temp = strchr(setup_string,
'@')+1;
252 len = strchr(temp,
'/') - temp;
261 temp = strchr(temp,
'/')+1;
276 mysql = mysql_init(NULL);
282 if (mysql_set_character_set(mysql,
"utf8"))
285 mysql_res = mysql_list_tables(mysql, NULL);
304 if (mysql_num_rows(mysql_res) <= 0)
308 while ((mysql_row = mysql_fetch_row(mysql_res))) {
319 mysql_free_result(mysql_res);
321 if (mysql_query(mysql,
"SELECT formatid FROM `" TABLE_FORMAT "`"))
324 mysql_res = mysql_use_result(mysql);
325 mysql_row = mysql_fetch_row(mysql_res);
336 mysql_free_result(mysql_res);
337 mysql_res = mysql_list_tables(mysql, NULL);
341 while ((mysql_row = mysql_fetch_row(mysql_res))) {
348 if (1 == create_dirs)
352 mysql_free_result(mysql_res);
356 if (mysql_query(mysql, drop_tdirs))
358 if (mysql_query(mysql, create_tdirs))
362 if (mysql_query(mysql, drop_tfiles))
364 if (mysql_query(mysql, create_tfiles))
368 if (mysql_query(mysql, drop_tformat))
370 if (mysql_query(mysql, create_tformat))
372 if (mysql_query(mysql, init_tformat))
383 if (mysql_errno(mysql))
384 mi_serror(
"An error occured: %s", mysql_error(mysql));
385 mysql_free_result(mysql_res);
389 mi_serror(
"Likely length overflow in configuration fields: "
390 "user: %zu/%u, pass: %zu/%u, db: %zu/%u, host: %zu/%u",
412 if (mysql_query(mysql,
"TRUNCATE TABLE `" TABLE_FILES "`"))
414 mysql_query(mysql,
"TRUNCATE TABLE `" TABLE_DIRS "`");
420 if (mysql_errno(mysql))
421 mi_rerror(
"An error occured: %s", mysql_error(mysql));
441 const unsigned long timestamp, MYSQL *mysql)
443 char *restrict sqlstr, *restrict query = NULL;
444 MYSQL_RES *mysql_res = NULL;
446 unsigned int myerrno = 0;
448 if (!(sqlstr =
apr_palloc(r->pool, 2*strlen(dirpath)+1)))
451 mysql_real_escape_string(mysql, sqlstr, dirpath, strlen(dirpath));
460 mysql_query(mysql,
"LOCK TABLES " TABLE_DIRS " WRITE");
467 mysql_res = mysql_store_result(mysql);
469 if (mysql_num_rows(mysql_res))
471 "WHERE `fullpath`='%s'", timestamp, sqlstr);
482 myerrno = mysql_errno(mysql);
484 query =
apr_pstrdup(r->pool, (
char *)mysql_error(mysql));
486 mysql_query(mysql,
"UNLOCK TABLES");
488 mysql_free_result(mysql_res);
494 mi_rerror(
"An error occured: %s", query);
517 char *restrict sqlstr, *restrict query = NULL;
520 if (!(sqlstr =
apr_palloc(r->pool, 2*strlen(curdir)+1)))
523 mysql_real_escape_string(mysql, sqlstr, curdir, strlen(curdir));
526 TABLE_DIRS " WHERE `fullpath` LIKE '%s%%')", sqlstr);
528 mysql_query(mysql,
"LOCK TABLES " TABLE_DIRS
" WRITE, " TABLE_FILES " WRITE");
530 if (mysql_query(mysql, query))
534 query =
apr_psprintf(r->pool,
"DELETE FROM `" TABLE_DIRS
"` WHERE `fullpath` LIKE '%s%%'", sqlstr);
543 mi_rerror(
"An error occured: %s", mysql_error(mysql));
544 mysql_query(mysql,
"UNLOCK TABLES");
573 MYSQL_RES *mysql_res = NULL;
576 char *restrict sqlstr = NULL, *restrict query = NULL;
582 if (
unlikely(!(sqlstr = malloc(2*strlen(path)+1))))
585 mysql_real_escape_string(mysql, sqlstr, path, strlen(path));
594 mysql_res = mysql_store_result(mysql);
596 if ((mysql_num_rows(mysql_res) == 0))
601 mysql_row = mysql_fetch_row(mysql_res);
608 stat(path, &dirstat);
610 test = (unsigned)atol(mysql_row[0]);
611 if (test < dirstat.st_mtime) {
620 mysql_free_result(mysql_res);
623 mi_rerror(
"An error occured: %s", mysql_error(mysql));
648 const char *
const filename)
652 MYSQL_RES *mysql_res = NULL;
655 char * restrict sqldirn = NULL, * restrict sqlbasen = NULL, * restrict query = NULL;
656 char *dirs = NULL, *bases = NULL, *dirn = NULL, *basen = NULL;
662 if (
unlikely(stat(filename, &statbuf)))
665 dirs = strdup(filename);
666 bases = strdup(filename);
670 dirn = dirname(dirs);
671 basen = basename(bases);
673 sqldirn = malloc(2*strlen(dirn)+1);
674 sqlbasen = malloc(2*strlen(basen)+1);
675 if (
unlikely(!sqldirn || !sqlbasen))
678 mysql_real_escape_string(mysql, sqldirn, dirn, strlen(dirn));
679 mysql_real_escape_string(mysql, sqlbasen, basen, strlen(basen));
683 "` WHERE `pid`=(SELECT `id` from `" TABLE_DIRS "` WHERE `fullpath`='%s')"
684 "AND `filename`='%s' COLLATE utf8_bin",
690 mysql_res = mysql_store_result(mysql);
693 if ((mysql_num_rows(mysql_res) == 0))
697 mysql_row = mysql_fetch_row(mysql_res);
704 (
unlikely((
unsigned)atol(mysql_row[1]) < statbuf.st_mtime)) )
713 mi_rerror(
"An error occured: %s", mysql_error(mysql));
715 mysql_free_result(mysql_res);
716 free(dirs), free(bases);
717 free(sqldirn), free(sqlbasen);
738 MYSQL_RES *mysql_res = NULL;
739 char * restrict sqldirn = NULL, * restrict sqlbasen = NULL, * restrict query = NULL;
740 char * restrict sqlalb = NULL, * restrict sqlart = NULL, * restrict sqltit = NULL, * restrict sqlgen = NULL;
741 char *dirs = NULL, *bases = NULL, *dirn = NULL, *basen = NULL;
742 unsigned int myerrno = 0;
759 dirs = strdup(filename);
760 bases = strdup(filename);
764 dirn = dirname(dirs);
765 basen = basename(bases);
767 sqldirn = malloc(2*strlen(dirn)+1);
768 sqlbasen = malloc(2*strlen(basen)+1);
769 if (
unlikely(!sqldirn || !sqlbasen))
772 mysql_real_escape_string(mysql, sqldirn, dirn, strlen(dirn));
773 mysql_real_escape_string(mysql, sqlbasen, basen, strlen(basen));
779 mysql_real_escape_string(mysql, sqlalb, p->
album, strlen(p->
album));
784 mysql_real_escape_string(mysql, sqlart, p->
artist, strlen(p->
artist));
789 mysql_real_escape_string(mysql, sqlgen, p->
genre, strlen(p->
genre));
793 mysql_real_escape_string(mysql, sqltit, p->
title, strlen(p->
title));
799 query =
apr_psprintf(r->pool,
"SELECT `id` FROM `" TABLE_DIRS
"` WHERE `fullpath`='%s'", sqldirn);
804 mysql_res = mysql_store_result(mysql);
808 if (
unlikely(mysql_num_rows(mysql_res) == 0))
811 mysql_free_result(mysql_res);
815 "AND pid=(SELECT `id` FROM `" TABLE_DIRS
"` WHERE `fullpath`='%s')",
821 mysql_res = mysql_store_result(mysql);
823 if (
unlikely(mysql_num_rows(mysql_res))) {
828 mysql_row = mysql_fetch_row(mysql_res);
831 "` SET cvers='%hi',filetype='%hu',flags='%hu',track='%hu',"
832 "posn='%hu',date='%hu',freq='%hu',length='%hu',"
833 "bitrate='%lu',size='%lu',mtime='%lu',title='%s'",
838 sqlalb ?
apr_psprintf(r->pool,
",album='%s'", sqlalb) :
",album=NULL",
839 sqlart ?
apr_psprintf(r->pool,
",artist='%s'", sqlart) :
",artist=NULL",
840 sqlgen ?
apr_psprintf(r->pool,
",genre='%s'", sqlgen) :
",genre=NULL",
841 apr_psprintf(r->pool,
" WHERE id='%lu'", (
unsigned long)atol(mysql_row[0])), NULL);
845 "` (`pid`,`cvers`,`filetype`,`flags`,`track`,`posn`,`date`,`freq`,"
846 "`length`,`bitrate`,`size`,`mtime`,`title`,`filename`,`album`,`artist`,"
848 "((SELECT `id` FROM `" TABLE_DIRS
"` WHERE `fullpath`='%s'),"
849 "'%hi','%hu','%hu','%hu','%hu','%hu','%hu','%hu',"
850 "'%lu','%lu','%lu','%s','%s',",
854 sqlalb ?
apr_psprintf(r->pool,
"'%s',", sqlalb) :
"NULL,",
855 sqlart ?
apr_psprintf(r->pool,
"'%s',", sqlart) :
"NULL,",
856 sqlgen ?
apr_psprintf(r->pool,
"'%s'", sqlgen) :
"NULL",
862 mysql_query(mysql, query);
865 myerrno = mysql_errno(mysql);
867 query =
apr_pstrdup(r->pool, (
char *)mysql_error(mysql));
871 mysql_query(mysql,
"UNLOCK TABLES");
877 mi_rerror(
"An error occured: %s", query);
880 mysql_free_result(mysql_res);
881 free(dirs), free(bases);
882 free(sqldirn), free(sqlbasen);
883 free(sqlalb), free(sqlart), free(sqlgen), free(sqltit);
920 const char *
const filename,
const char *
const uri, MYSQL *mysql,
unsigned long soptions)
923 MYSQL_RES *mysql_res;
927 mysql_dir *mhead = NULL, *mdir = NULL, *ret = NULL;
928 char *restrict sqlstr = NULL, *restrict query = NULL;
929 char *restrict basen = NULL, *restrict fullpath = NULL;
930 unsigned long nb = 0, size = 0;
931 const size_t fnlen = strlen(filename);
937 sqlstr = malloc(2*fnlen+1);
941 mysql_real_escape_string(mysql, sqlstr, filename, fnlen);
950 "`fullpath` LIKE '%s/%%' AND (LOCATE('/', fullpath, %lu)=0)",
951 sqlstr, strlen(sqlstr)+2);
956 mysql_res = mysql_use_result(mysql);
958 while ((mysql_row = mysql_fetch_row(mysql_res))) {
962 if (
likely(basen && mdir)) {
963 mdir->d_name = basen;
969 mysql_free_result(mysql_res);
978 "(SELECT `id` from `" TABLE_DIRS "` WHERE `fullpath`='%s')",
987 mysql_real_escape_string(mysql, escsearch, conf->
search, strlen(conf->
search));
988 query =
apr_pstrcat(pool, query,
" AND MATCH(`filename`,`title`,`artist`,`album`) AGAINST ('",
989 escsearch,
"')", NULL);
995 mysql_res = mysql_use_result(mysql);
998 fullpath = malloc(fnlen + 2);
1003 strncpy(fullpath, filename, fnlen);
1004 fullpath[fnlen] =
'/';
1005 fullpath[fnlen+1] =
'\0';
1007 while ((mysql_row = mysql_fetch_row(mysql_res))) {
1013 if (
likely(basen && mdir)) {
1014 mdir->d_name = basen;
1022 struct stat statbuf;
1023 fullpath = realloc(fullpath, fnlen + 1 + strlen(mysql_row[
SQL_CDATAN]) + 1);
1028 fullpath[fnlen+1] =
'\0';
1029 strncat(fullpath, mysql_row[SQL_CDATAN], strlen(mysql_row[SQL_CDATAN]));
1035 if (
unlikely(stat(fullpath, &statbuf))) {
1036 mi_rdebug(
"Trashing cache for: %s", filename);
1037 mysql_free_result(mysql_res);
1046 if (
likely(basen && mdir)) {
1047 mdir->d_name = basen;
1059 p->
file += strlen(r->parsed_uri.path);
1071 mysql_free_result(mysql_res);
1076 pack->
fsize += size;
1088 mi_rerror(
"An error occured: %s", mysql_error(mysql));
1089 free(sqlstr), free(fullpath);
1114 const char *
const uri,
unsigned long soptions)
1121 struct stat dirstat;
1141 stat(filename, &dirstat);
1167 const char *ret = NULL;
1194 MYSQL *mysql = NULL;
1199 mysql = mysql_init(NULL);
1209 if (
unlikely(mysql_set_character_set(mysql,
"utf8"))) {
1254 static const char biniou[] =
"mysql://";
1257 if (strncmp(biniou, setup_string, 8) == 0) {