1 /*
2 * Copyright (C) 2009-2015 Christian Heckendorf <heckendorfc@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "dbact.h"
19 #include "defs.h"
20 #include "util.h"
21 #include "admin.h"
22 #include "plugins/plugin.h"
23
24
harp_sqlite3_exec(sqlite3 * connection,const char * sql,int (* callback)(void *,int,char **,char **),void * arg,char ** errmsg)25 int harp_sqlite3_exec(sqlite3 *connection, const char *sql, int (*callback)(void*,int,char**,char**), void *arg, char **errmsg){
26 return sqlite3_exec(connection,sql,callback,arg,errmsg);
27 }
28
db_exec_file(char * file)29 int db_exec_file(char *file){
30 FILE *ffd;
31 int x=0,querysize=200,ret=0;
32 char *query=malloc(sizeof(char)*querysize);
33 char *err;
34
35 if(!query){
36 debug(2,"Cannot malloc query");
37 return 1;
38 }
39
40 if((ffd=fopen(file,"r"))){
41 while(fgets((query+x),querysize-x,ffd)){
42 //fprintf(stderr,"Next batch\n%x %x ",*ptr, query[x]);
43 for(;x<querysize-1 && query[x]!='\n' && query[x];x++);
44 if(x<querysize-1){
45 query[x]=' ';
46 query[++x]=0;
47 }
48 if(!sqlite3_complete(query)){
49 if(x>=querysize-100){
50 querysize+=100;
51 if(querysize<2000)
52 query=realloc(query,querysize);
53 else{
54 debug(2,"Limit reached");
55 ret=1;break;
56 }
57 if(!query){
58 debug(2,"Not enough memory");
59 ret=1;break;
60 }
61 }
62 continue;
63 }
64
65 if(harp_sqlite3_exec(conn,query,NULL,NULL,&err)!=SQLITE_OK){
66 if(err){
67 fprintf(stderr,"SQL Error: %s\n",err);
68 sqlite3_free(err);
69 }
70 debug(2,"harp_sqlite3_exec error.");
71 ret=1;break;
72 }
73 x=0;
74 }
75 fclose(ffd);
76 }
77 else{
78 fprintf(stderr,"Cannot open file\n");
79 ret=1;
80 }
81 free(query);
82 return ret;
83 }
84
upgrade_0()85 static void upgrade_0(){
86 int i;
87 int type;
88 char query[200];
89 char *newview="CREATE VIEW SongPubInfo AS \
90 SELECT Song.Title AS SongTitle, Song.Location AS Location, \
91 Album.Title AS AlbumTitle, Artist.Name AS ArtistName, \
92 Song.TypeID AS PluginID, Song.Length AS Length, \
93 Song.Rating AS Rating, \
94 Song.SongID AS SongID, Song.Track AS SongTrack \
95 FROM Song \
96 INNER JOIN Album ON Song.AlbumID=Album.AlbumID \
97 NATURAL JOIN AlbumArtist \
98 INNER JOIN Artist ON AlbumArtist.ArtistID=Artist.ArtistID";
99
100 for(i=0;i<PLUGIN_NULL;i++){
101 if(plugin_head[i]==NULL)
102 type=-1;
103 else
104 type=i;
105
106 sprintf(query,"UPDATE Song SET TypeID=%d WHERE TypeID=(SELECT TypeID FROM FileType WHERE Name='%s' LIMIT 1)",i,plugin_head[i]->name);
107 harp_sqlite3_exec(conn,query,NULL,NULL,NULL);
108 }
109
110 harp_sqlite3_exec(conn,"DROP VIEW SongPubInfo",NULL,NULL,NULL);
111 harp_sqlite3_exec(conn,newview,NULL,NULL,NULL);
112 }
113
114 typedef void (*db_up)();
115 static db_up upgrade_db_from[]={
116 upgrade_0,
117 };
118
dbInit()119 unsigned int dbInit(){
120 char temp[255];
121 //strcpy(temp,DB);
122 sprintf(temp,"%s%s",DB_PATH,DB);
123 expand(temp);
124 if(sqlite3_open_v2(temp,&conn,SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE,NULL)!=SQLITE_OK){
125 printf("Database not found. Attempting to create\n");
126 // Try creating
127 strcpy(temp,DB_PATH);
128 expand(temp);
129 mkdir(temp,0700);
130 sprintf(temp,"%s%s",DB_PATH,DB);
131 expand(temp);
132 if(sqlite3_open(temp,&conn)!=SQLITE_OK){
133 printf("Database connection error: %s\n",sqlite3_errmsg(conn));
134 return 0;
135 }
136 sprintf(temp,"%s/harp/create.sql",SHARE_PATH);
137 if(db_exec_file(temp)){
138 printf("Error creating database from file:\n\t%s\n",temp);
139 sqlite3_close(conn);
140 return 0;
141 }
142 /*
143 if(autoAddPlugins()!=HARP_RET_OK){
144 fprintf(stderr,"Automatic plugin loading failed.\nPlease add any installed plugins to the database with harp -a\n");
145 }
146 */
147 }
148 else{
149 /* Upgrade DB */
150 int vnum=0;
151 harp_sqlite3_exec(conn,"SELECT Version FROM DBInfo",uint_return_cb,&vnum,NULL);
152 if(vnum!=DB_VERSION){
153 sprintf(temp,"Upgrading database from %d to %d\n",vnum,DB_VERSION);
154 debug(1,temp);
155 while(vnum<DB_VERSION){
156 upgrade_db_from[vnum++]();
157 }
158 harp_sqlite3_exec(conn,"CREATE TABLE IF NOT EXISTS DBInfo(Version integer primary key)",uint_return_cb,&vnum,NULL);
159 harp_sqlite3_exec(conn,"DELETE FROM DBInfo",NULL,NULL,NULL);
160 harp_sqlite3_exec(conn,"INSERT INTO DBInfo(Version) VALUES(" varstr(DB_VERSION) ")",NULL,NULL,NULL);
161 }
162 }
163 return 1;
164 }
165
dbiInit(struct dbitem * dbi)166 void dbiInit(struct dbitem *dbi){
167 dbi->result=NULL;
168 dbi->row=NULL;
169 dbi->err=NULL;
170 }
171
dbiClean(struct dbitem * dbi)172 void dbiClean(struct dbitem *dbi){
173 if(dbi->row!=NULL){
174 free(dbi->row);
175 dbi->row=NULL;
176 }
177 if(dbi->result!=NULL){
178 sqlite3_free_table(dbi->result);
179 dbi->result=NULL;
180 }
181 }
182
fetch_row(struct dbitem * dbi)183 int fetch_row(struct dbitem *dbi){
184 if(dbi->row_count==0)return 0;
185
186 int x;
187 for(x=0;x<dbi->column_count;x++)
188 dbi->row[x]=dbi->result[dbi->current_row+x];
189
190 x=dbi->current_row<(dbi->row_count+1)*dbi->column_count?1:0;
191 dbi->current_row+=dbi->column_count;
192 return x;
193 }
194
fetch_row_at(struct dbitem * dbi,int index)195 int fetch_row_at(struct dbitem *dbi,int index){
196 int x;
197 if(index>=dbi->row_count || index<0)return 0;
198 for(x=0;x<dbi->column_count;x++)
199 dbi->row[x]=dbi->result[index+x];
200 return 1;
201 }
202
fetch_column_at(struct dbitem * dbi,int index)203 char ** fetch_column_at(struct dbitem *dbi, int index){
204 int x;
205 char **col;
206 if(!(col=malloc(sizeof(char*)*dbi->row_count)))return NULL;
207 index+=dbi->column_count;
208 for(x=0;x<dbi->row_count;x++)
209 col[x]=dbi->result[index+(x*dbi->column_count)];
210 return col;
211 }
212
doQuery(const char * querystr,struct dbitem * dbi)213 int doQuery(const char *querystr,struct dbitem *dbi){
214 dbiClean(dbi);
215 sqlite3_get_table(conn,querystr,&dbi->result,&dbi->row_count,&dbi->column_count,&dbi->err);
216 if(dbi->err!=NULL){
217 fprintf(stderr,"Database query error: %s\n",dbi->err);
218 sqlite3_free(dbi->err);
219 dbi->err=NULL;
220 return -1;
221 }
222 if(!dbi->column_count)
223 return sqlite3_changes(conn);
224
225 dbi->current_row=0;
226 if(!(dbi->row=malloc(sizeof(char*)*dbi->column_count))){
227 debug(2,"Malloc failed (dbi->row).");
228 return -1;
229 }
230 fetch_row(dbi);
231 return dbi->row_count;
232 }
233
uint_return_cb(void * arg,int col_count,char ** row,char ** titles)234 int uint_return_cb(void *arg, int col_count, char **row, char **titles){
235 *(unsigned int*)arg=(unsigned int)strtol(*row,NULL,10);
236 return 0;
237 }
238
str_return_cb(void * arg,int col_count,char ** row,char ** titles)239 int str_return_cb(void *arg, int col_count, char **row, char **titles){
240 arg=strdup(*row);
241 return 0;
242 }
243
titlequery_titles_cb(void * data,int col_count,char ** row,char ** titles)244 static int titlequery_titles_cb(void *data, int col_count, char **row, char **titles){
245 struct titlequery_data *arg=(struct titlequery_data*) data;
246 int x,templen,len=arg->maxwidth+3;
247 col_count--;
248 for(x=0;x<col_count;x++){
249 if(!arg->exception[x]){
250 len=printf("[%.*s]",arg->maxwidth,titles[x]);
251 printf("%*c",(arg->maxwidth+3)-len,' ');
252 }
253 else{
254 templen=printf("[%s]",titles[x]);
255 if(templen>arg->exlen[x])arg->exlen[x]=templen;
256 printf("%*c",(arg->exlen[x]-templen)+1,' ');
257 }
258 }
259 if(!arg->exception[x]){ // Ignore end spacing on final field
260 printf("[%.*s]",arg->maxwidth,titles[x]);
261 }
262 else
263 printf("[%s] ",titles[x]);
264 printf("\n");
265 return 1;
266 }
267
titlequery_columns_cb(void * data,int col_count,char ** row,char ** titles)268 static int titlequery_columns_cb(void *data, int col_count, char **row, char **titles){
269 struct titlequery_data *arg=(struct titlequery_data*) data;
270 int x,templen;
271 char *ptr;
272 col_count--;
273 for(x=0;x<col_count;x++){
274 if(arg->exception[x]){
275 for(ptr=row[x];*ptr;++ptr);
276 templen=(ptr-row[x])+2;
277 if(templen>arg->exlen[x])arg->exlen[x]=templen;
278 }
279 }
280 return 0;
281 }
282
titlequery_cb(void * data,int col_count,char ** row,char ** titles)283 static int titlequery_cb(void *data, int col_count, char **row, char **titles){
284 struct titlequery_data *arg=(struct titlequery_data*) data;
285 int x,templen,len=arg->maxwidth+3;
286 col_count--;
287 for(x=0;x<col_count;x++){
288 if(!arg->exception[x]){
289 len=printf("[%.*s]",arg->maxwidth,row[x]);
290 printf("%*c",(arg->maxwidth+3)-len,' ');
291 }
292 else{
293 templen=printf("[%s]",row[x]);
294 printf("%*c",(arg->exlen[x]-templen)+1,' ');
295 }
296 }
297 if(!arg->exception[x]){ // Ignore end spacing on final field
298 printf("[%.*s]",arg->maxwidth,row[x]);
299 }
300 else
301 printf("[%s] ",row[x]);
302 printf("\n");
303 arg->count++;
304 return 0;
305 }
306
doTitleQuery(const char * querystr,int * exception,int maxwidth)307 int doTitleQuery(const char *querystr,int *exception, int maxwidth){
308 struct titlequery_data tqd;
309
310 int defexception[10];
311 if(!exception){
312 int x;
313 for(x=1;x<10;x++)defexception[x]=listconf.exception;
314 exception=defexception;
315 }
316
317 tqd.count=0;
318 tqd.exception=exception;
319 tqd.maxwidth=maxwidth;
320 tqd.exlen=calloc(10,sizeof(int));
321
322 harp_sqlite3_exec(conn,querystr,titlequery_columns_cb,&tqd,NULL);
323 harp_sqlite3_exec(conn,querystr,titlequery_titles_cb,&tqd,NULL);
324 harp_sqlite3_exec(conn,querystr,titlequery_cb,&tqd,NULL);
325
326 free(tqd.exlen);
327 return tqd.count;
328 }
329
batch_tempplaylistsong_insert_cb(void * arg,int col_count,char ** row,char ** titles)330 int batch_tempplaylistsong_insert_cb(void *arg, int col_count, char **row, char **titles){
331 struct insert_tps_arg *data=(struct insert_tps_arg*)arg;
332
333 sprintf(data->query,"INSERT INTO TempPlaylistSong(SongID,\"Order\") VALUES(%s,%d)",*row,data->order);
334 harp_sqlite3_exec(conn,data->query,NULL,NULL,NULL);
335
336 data->order++;
337 return 0;
338 }
339
createTempPlaylistSong()340 void createTempPlaylistSong(){
341 harp_sqlite3_exec(conn,"CREATE TEMP TABLE IF NOT EXISTS TempPlaylistSong( PlaylistSongID integer primary key, SongID integer not null, \"Order\" integer NOT NULL)",NULL,NULL,NULL);
342 }
343