Esempio n. 1
0
/** Free the argument list created by make_arglist()
 *
 */
void free_arglist(void *db, wg_query_arg *arglist, int sz) {
  if(arglist) {
    int i;
    for(i=0; i<sz; i++) {
      if(arglist[i].value != WG_ILLEGAL) {
        wg_free_query_param(db, arglist[i].value);
      }
    }
    free(arglist);
  }
}
Esempio n. 2
0
char* search(char* database, char* inparams[], char* invalues[], int incount, int* hformat) {
  int i,rcount,gcount,itmp;
  wg_int type=0;
  char* fields[MAXPARAMS];
  char* values[MAXPARAMS];
  char* compares[MAXPARAMS];
  char* types[MAXPARAMS];
  int fcount=0, vcount=0, ccount=0, tcount=0;
  int from=0;
  int count=MAXCOUNT;
  void* db=NULL; // actual database pointer
  void* rec;
  char* res;
  int res_size=INITIAL_MALLOC;
  wg_query *wgquery;  // query datastructure built later
  wg_query_arg wgargs[MAXPARAMS];
  wg_int lock_id=0;  // non-0 iff lock set
  int nosearch=0; // 1 iff no search parameters given, use scan
  int maxdepth=MAX_DEPTH_DEFAULT; // rec depth limit for printer
  int showid=0; // add record id as first extra elem: 0: no, 1: yes
  int format=1; // 0: csv, 1:json
  int escape=2; // string special chars escaping:  0: just ", 1: urlencode, 2: json, 3: csv
  char errbuf[200]; // used for building variable-content input param error strings only
  char* strbuffer; // main result string buffer start (malloced later)
  int strbufferlen; // main result string buffer length
  char* strbufferptr; // current output location ptr in the main result string buffer

  // -------check and parse cgi parameters, attach database ------------

  // set params to defaults
  for(i=0;i<MAXPARAMS;i++) {
    fields[i]=NULL; values[i]=NULL; compares[i]=NULL; types[i]=NULL;
  }
  // find search parameters
  for(i=0;i<incount;i++) {
    if (strncmp(inparams[i],"field",MAXQUERYLEN)==0) {
      fields[fcount++]=invalues[i];
    } else if (strncmp(inparams[i],"value",MAXQUERYLEN)==0) {
      values[vcount++]=invalues[i];
    } else if (strncmp(inparams[i],"compare",MAXQUERYLEN)==0) {
      compares[ccount++]=invalues[i];
    } else if (strncmp(inparams[i],"type",MAXQUERYLEN)==0) {
      types[tcount++]=invalues[i];
    } else if (strncmp(inparams[i],"from",MAXQUERYLEN)==0) {
      from=atoi(invalues[i]);
    } else if (strncmp(inparams[i],"count",MAXQUERYLEN)==0) {
      count=atoi(invalues[i]);
    } else if (strncmp(inparams[i],"depth",MAXQUERYLEN)==0) {
      maxdepth=atoi(invalues[i]);
    } else if (strncmp(inparams[i],"showid",MAXQUERYLEN)==0) {
      if (strncmp(invalues[i],"yes",MAXQUERYLEN)==0) showid=1;
      else if (strncmp(invalues[i],"no",MAXQUERYLEN)==0) showid=0;
      else {
        snprintf(errbuf,100,UNKNOWN_PARAM_VALUE_ERR,invalues[i],inparams[i]);
        errhalt(errbuf);
      }
    } else if (strncmp(inparams[i],"format",MAXQUERYLEN)==0) {
      if (strncmp(invalues[i],"csv",MAXQUERYLEN)==0) format=0;
      else if (strncmp(invalues[i],"json",MAXQUERYLEN)==0) format=1;
      else {
        snprintf(errbuf,100,UNKNOWN_PARAM_VALUE_ERR,invalues[i],inparams[i]);
        errhalt(errbuf);
      }
    } else if (strncmp(inparams[i],"escape",MAXQUERYLEN)==0) {
      if (strncmp(invalues[i],"no",MAXQUERYLEN)==0) escape=0;
      else if (strncmp(invalues[i],"url",MAXQUERYLEN)==0) escape=1;
      else if (strncmp(invalues[i],"json",MAXQUERYLEN)==0) escape=2;
      else {
        snprintf(errbuf,100,UNKNOWN_PARAM_VALUE_ERR,invalues[i],inparams[i]);
        errhalt(errbuf);
      }
    } else if (strncmp(inparams[i],"db",MAXQUERYLEN)==0) {
      // correct parameter, no action here
    } else if (strncmp(inparams[i],"op",MAXQUERYLEN)==0) {
      // correct parameter, no action here
    } else {
      // incorrect/unrecognized parameter
      snprintf(errbuf,100,UNKNOWN_PARAM_ERR,inparams[i]);
      errhalt(errbuf);
    }
  }
  // all parameters and values were understood
  if (format==0) {
    // csv
    maxdepth=0; // record structure not printed for csv
    escape=3; // only " replaced with ""
    *hformat=0; // store to caller for content-type header
    global_format=0; // for error handler only
  }
  // check search parameters
  if (!fcount) {
    if (vcount || ccount || tcount) errhalt(NO_FIELD_ERR);
    else nosearch=1;
  }
  // attach to database
  db = wg_attach_existing_database(database);
  global_db=db;
  if (!db) errhalt(DB_ATTACH_ERR);
  res=malloc(res_size);
  if (!res) {
    err_clear_detach_halt(db,0,MALLOC_ERR);
  }
  // database attached OK
  // create output string buffer (may be reallocated later)

  strbuffer=str_new(INITIAL_MALLOC);
  strbufferlen=INITIAL_MALLOC;
  strbufferptr=strbuffer;
  if (nosearch) {
    // ------- special case without real search: just output records ---
    gcount=0;
    rcount=0;
    lock_id = wg_start_read(db); // get read lock
    global_lock_id=lock_id; // only for handling errors
    if (!lock_id) err_clear_detach_halt(db,0,LOCK_ERR);
    str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
    if (format!=0) {
      // json
      snprintf(strbufferptr,MIN_STRLEN,"[\n");
      strbufferptr+=2;
    }
    if (maxdepth>MAX_DEPTH_HARD) maxdepth=MAX_DEPTH_HARD;
    rec=wg_get_first_record(db);
    do {
      if (rcount>=from) {
        gcount++;
        if (gcount>count) break;
        str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
        if (gcount>1 && format!=0) {
          // json and not first row
          snprintf(strbufferptr,MIN_STRLEN,",\n");
          strbufferptr+=2;
        }
        sprint_record(db,rec,&strbuffer,&strbufferlen,&strbufferptr,format,showid,0,maxdepth,escape);
        if (format==0) {
          // csv
          str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
          snprintf(strbufferptr,MIN_STRLEN,"\r\n");
          strbufferptr+=2;
        }
      }
      rec=wg_get_next_record(db,rec);
      rcount++;
    } while(rec!=NULL);
    if (!wg_end_read(db, lock_id)) {  // release read lock
      err_clear_detach_halt(db,lock_id,LOCK_RELEASE_ERR);
    }
    global_lock_id=0; // only for handling errors
    wg_detach_database(db);
    global_db=NULL; // only for handling errors
    str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
    if (format!=0) {
      // json
      snprintf(strbufferptr,MIN_STRLEN,"\n]");
      strbufferptr+=3;
    }
    return strbuffer;
  }

  // ------------ normal search case: ---------

  // create a query list datastructure

  for(i=0;i<fcount;i++) {
    // field num
    if (!isint(fields[i])) err_clear_detach_halt(db,0,NO_FIELD_ERR);
    itmp=atoi(fields[i]);
    // column to compare
    wgargs[i].column = itmp;
    // comparison op: default equal
    wgargs[i].cond = encode_incomp(db,compares[i]);
    // valuetype: default guess from value later
    type=encode_intype(db,types[i]);
    // encode value to compare with
    wgargs[i].value =  encode_invalue(db,values[i],type);
  }

  // make the query structure and read-lock the database before!

  lock_id = wg_start_read(db); // get read lock
  global_lock_id=lock_id; // only for handling errors
  if (!lock_id) err_clear_detach_halt(db,lock_id,LOCK_ERR);
  wgquery = wg_make_query(db, NULL, 0, wgargs, i);
  if (!wgquery) err_clear_detach_halt(db,lock_id,QUERY_ERR);

  // actually perform the query

  rcount=0;
  gcount=0;
  str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
  if (format!=0) {
    // json
    snprintf(strbufferptr,MIN_STRLEN,"[\n");
    strbufferptr+=2;
  }
  if (maxdepth>MAX_DEPTH_HARD) maxdepth=MAX_DEPTH_HARD;
  while((rec = wg_fetch(db, wgquery))) {
    if (rcount>=from) {
      gcount++;
      str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
      if (gcount>1 && format!=0) {
        // json and not first row
        snprintf(strbufferptr,MIN_STRLEN,",\n");
        strbufferptr+=2;
      }
      sprint_record(db,rec,&strbuffer,&strbufferlen,&strbufferptr,format,showid,0,maxdepth,escape);
      if (format==0) {
        // csv
        str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
        snprintf(strbufferptr,MIN_STRLEN,"\r\n");
        strbufferptr+=2;
      }
    }
    rcount++;
    if (gcount>=count) break;
  }
  // free query datastructure, release lock, detach

  for(i=0;i<fcount;i++) wg_free_query_param(db, wgargs[i].value);
  wg_free_query(db,wgquery);
  if (!wg_end_read(db, lock_id)) {  // release read lock
    err_clear_detach_halt(db,lock_id,LOCK_RELEASE_ERR);
  }
  global_lock_id=0; // only for handling errors
  wg_detach_database(db);
  global_db=NULL; // only for handling errors
  str_guarantee_space(&strbuffer,&strbufferlen,&strbufferptr,MIN_STRLEN);
  if (format!=0) {
    // json
    snprintf(strbufferptr,MIN_STRLEN,"\n]");
    strbufferptr+=3;
  }
  return strbuffer;
}
Esempio n. 3
0
static char* search(thread_data_p tdata, char* inparams[], char* invalues[], 
             int incount, int opcode) {
  char* database=tdata->database;             
  char *token=NULL;             
  int i,j,x,itmp;
  wg_int type=0;
  char* fields[MAXPARAMS]; // search fields
  char* values[MAXPARAMS]; // search values
  char* compares[MAXPARAMS]; // search comparisons
  char* types[MAXPARAMS]; // search value types
  char* cids=NULL;             
  wg_int ids[MAXIDS];  // select these ids only         
  int fcount=0, vcount=0, ccount=0, tcount=0; // array el counters for above
  char* sfields[MAXPARAMS]; // set / selected fields
  char* svalues[MAXPARAMS]; // set field values
  char* stypes[MAXPARAMS];  // set field types  
  int sfcount; // array el counters for above              
  int from=0;             
  unsigned long count,rcount,gcount,handlecount;
  void* db=NULL; // actual database pointer
  void *rec, *oldrec; 
  char* res;
  wg_query *wgquery;  // query datastructure built later
  wg_query_arg wgargs[MAXPARAMS]; 
  wg_int lock_id=0;  // non-0 iff lock set
  int searchtype=0; // 0: full scan, 1: record ids, 2: by fields             
  char errbuf[ERRBUF_LEN]; // used for building variable-content input param error strings only               
  
  // default max nr of rows shown/handled
  if (opcode==COUNT_CODE) count=LONG_MAX;  
  else count=MAXCOUNT;
  // -------check and parse cgi parameters, attach database ------------
  // set params to defaults
  for(i=0;i<MAXPARAMS;i++) {
    fields[i]=NULL; values[i]=NULL; compares[i]=NULL; types[i]=NULL;
    sfields[i]=NULL; svalues[i]=NULL; stypes[i]=NULL;
  }
  // set printing params to defaults
  tdata->format=1; // 1: json
  tdata->maxdepth=MAX_DEPTH_DEFAULT; // rec depth limit for printer
  tdata->showid=0; // add record id as first extra elem: 0: no, 1: yes
  tdata->strenc=2; // string special chars escaping:  0: just ", 1: urlencode, 2: json, 3: csv
  // find search parameters
  for(i=0;i<incount;i++) {
    if (strncmp(inparams[i],"recids",MAXQUERYLEN)==0) {
      cids=invalues[i];         
      x=0;     
      // set ids to defaults
      for(j=0;j<MAXIDS;j++) ids[j]=0;
      // split csv int list to ids int array      
      for(j=0;j<strlen(cids);j++) {
        if (atoi(cids+j) && atoi(cids+j)>0) ids[x++]=atoi(cids+j);        
        if (x>=MAXIDS) break;
        for(;j<strlen(cids) && cids[j]!=','; j++) {};
      }             
    } else if (strncmp(inparams[i],"fld",MAXQUERYLEN)==0) {
      res=handle_fld_param(tdata,inparams[i],invalues[i],
                           &sfields[sfcount],&svalues[sfcount],&stypes[sfcount],sfcount,errbuf);
      if (res!=NULL) return res; // return error string
      sfcount++;     
    } else if (strncmp(inparams[i],"field",MAXQUERYLEN)==0) {
      fields[fcount++]=invalues[i];       
    } else if (strncmp(inparams[i],"value",MAXQUERYLEN)==0) {
      values[vcount++]=invalues[i];
    } else if (strncmp(inparams[i],"compare",MAXQUERYLEN)==0) {
      compares[ccount++]=invalues[i];
    } else if (strncmp(inparams[i],"type",MAXQUERYLEN)==0) {
      types[tcount++]=invalues[i];
    } else if (strncmp(inparams[i],"from",MAXQUERYLEN)==0) {      
      from=atoi(invalues[i]);
    } else if (strncmp(inparams[i],"count",MAXQUERYLEN)==0) {      
      count=atoi(invalues[i]);    
    } else {  
      // handle generic parameters for all queries: at end of param check
      res=handle_generic_param(tdata,inparams[i],invalues[i],&token,errbuf);      
      if (res!=NULL) return res;  // return error string
    }      
  }
  // authorization
  if (opcode==DELETE_CODE || opcode==UPDATE_CODE) {
    if (!authorize(WRITE_LEVEL,tdata,database,token))
      return errhalt(NOT_AUTHORIZED_ERR,tdata); 
  } else {  
    if (!authorize(READ_LEVEL,tdata,database,token))
      return errhalt(NOT_AUTHORIZED_ERR,tdata);
  }  
  // all parameters and values were understood 
  if (tdata->format==0) {
    // csv     
    tdata->maxdepth=0; // record structure not printed for csv
    tdata->strenc=3; // only " replaced with ""
  }  
  // check search parameters
  if (cids!=NULL) {
    // query by record ids
    if (fcount) return errhalt(RECIDS_COMBINED_ERR,tdata);
    searchtype=1;
  } else if (!fcount) {
    // no search fields given
    if (vcount || ccount || tcount) return errhalt(NO_FIELD_ERR,tdata);
    else searchtype=0; // scan everything
  } else {
    // search by fields
    searchtype=2;
  }    
  // attach to database
  db=op_attach_database(tdata,database,READ_LEVEL);
  if (!db) return errhalt(DB_ATTACH_ERR,tdata);   
  // database attached OK
  // create output string buffer (may be reallocated later)  
  tdata->buf=str_new(INITIAL_MALLOC);
  if (tdata->buf==NULL) return errhalt(MALLOC_ERR,tdata);
  tdata->bufsize=INITIAL_MALLOC;
  tdata->bufptr=tdata->buf; 
  // check printing depth
  if (tdata->maxdepth>MAX_DEPTH_HARD) tdata->maxdepth=MAX_DEPTH_HARD;  
  // initial print
  if(!op_print_data_start(tdata,opcode==SEARCH_CODE))
  return err_clear_detach_halt(MALLOC_ERR,tdata);
  // zero counters
  rcount=0;
  gcount=0;  
  handlecount=0; // actual nr of records handled
  // get lock
  if (tdata->realthread && tdata->common->shutdown) return NULL; // for multithreading only
  lock_id = wg_start_read(db); // get read lock
  tdata->lock_id=lock_id;
  tdata->lock_type=READ_LOCK_TYPE;
  if (!lock_id) return err_clear_detach_halt(LOCK_ERR,tdata);
  // handle one of the cases
  if (searchtype==0) {
    // ------- full scan case  ---     
    rec=wg_get_first_record(db);
    while (rec!=NULL) {    
      if (rcount>=from) {
        gcount++;
        if (gcount>count) break;  
        if (opcode==COUNT_CODE) { 
          handlecount++; 
        } else if (opcode==SEARCH_CODE) {
          itmp=op_print_record(tdata,rec,gcount);
          if (!itmp) return err_clear_detach_halt(MALLOC_ERR,tdata);
        } else if (opcode==UPDATE_CODE) {
          itmp=op_update_record(tdata,db,rec,0,0);
          if (!itmp) handlecount++;
        }
      }
      oldrec=rec;
      rec=wg_get_next_record(db,rec);
      if (opcode==DELETE_CODE) {
        x=wg_get_record_len(db,oldrec);
        if (x>0) {
          itmp=op_delete_record(tdata,oldrec);
          if (!itmp) handlecount++;
          //else err_clear_detach_halt(DELETE_ERR,tdata);
        }  
      } 
      rcount++;
    }   
  } else if (searchtype==1) {
    // ------------ search by record ids: ------------               
    for(j=0; ids[j]!=0 && j<MAXIDS; j++) {    
      x=wg_get_encoded_type(db,ids[j]);
      if (x!=WG_RECORDTYPE) continue;
      rec=wg_decode_record(db,ids[j]);    
      if (rec==NULL) continue;
      x=wg_get_record_len(db,rec);
      if (x<=0) continue;      
      gcount++;
      if (gcount>count) break; 
      if (opcode==COUNT_CODE) handlecount++;
      else if (opcode==SEARCH_CODE) {
        itmp=op_print_record(tdata,rec,gcount);
        if (!itmp) return err_clear_detach_halt(MALLOC_ERR,tdata);
      } else if (opcode==UPDATE_CODE) {
          itmp=op_update_record(tdata,db,rec,0,0);
          if (!itmp) handlecount++;         
      } else if (opcode==DELETE_CODE) {
        // test that db is not null, otherwise we may corrupt the database
        oldrec=wg_get_first_record(db);
        if (oldrec!=NULL) {
          //wg_int objecthead=dbfetch((void*)db,(void*)rec);
          //printf("isfreeobject %d\n",isfreeobject((int)objecthead));
          wg_print_record(db,rec);
          itmp=op_delete_record(tdata,rec);
          printf("deletion result %d\n",itmp);
          if (!itmp) handlecount++;
          //else return err_clear_detach_halt(DELETE_ERR,tdata);        
        }  
      }      
    }           
  } else if (searchtype==2) {
    // ------------by field search case: ---------

    // create a query list datastructure    
    for(i=0;i<fcount;i++) {   
      // field num    
      if (!isint(fields[i])) return err_clear_detach_halt(NO_FIELD_ERR,tdata);
      itmp=atoi(fields[i]);
      if(itmp<0) return err_clear_detach_halt(NO_FIELD_ERR,tdata);
      // column to compare
      wgargs[i].column = itmp;    
      // comparison op: default equal
      wgargs[i].cond = encode_incomp(db,compares[i]);
      if (wgargs[i].cond==BAD_WG_VALUE) return err_clear_detach_halt(COND_ERR,tdata);    
      // valuetype: default guess from value later
      type=encode_intype(db,types[i]); 
      if (type==BAD_WG_VALUE) return err_clear_detach_halt(INTYPE_ERR,tdata);
      // encode value to compare with   
      wgargs[i].value =  encode_invalue(db,values[i],type);        
      if (wgargs[i].value==WG_ILLEGAL) return err_clear_detach_halt(INTYPE_ERR,tdata);
    }   
    
    // make the query structure       
    wgquery = wg_make_query(db, NULL, 0, wgargs, i);
    if (!wgquery) return err_clear_detach_halt(QUERY_ERR,tdata);
    
    // actually perform the query           
    if (tdata->maxdepth>MAX_DEPTH_HARD) tdata->maxdepth=MAX_DEPTH_HARD;
    while((rec = wg_fetch(db, wgquery))) {
      if (rcount>=from) {
        gcount++;                           
        if (opcode==COUNT_CODE) handlecount++;
        else if (opcode==SEARCH_CODE) {
          itmp=op_print_record(tdata,rec,gcount);
          if (!itmp) return err_clear_detach_halt(MALLOC_ERR,tdata);
        } else if (opcode==UPDATE_CODE) {
          itmp=op_update_record(tdata,db,rec,0,0);
          if (!itmp) handlecount++;          
        } else if (opcode==DELETE_CODE) {
          itmp=op_delete_record(tdata,rec);
          if (!itmp) handlecount++;
          //else return err_clear_detach_halt(DELETE_ERR,tdata);  
        }
      }  
      rcount++;
      if (gcount>=count) break;    
    }   
    // free query datastructure, 
    for(i=0;i<fcount;i++) wg_free_query_param(db, wgargs[i].value);
    wg_free_query(db,wgquery); 
  }
  // ----- cases  handled  ------
  // print a single number for count and delete
  if (opcode==COUNT_CODE || opcode==DELETE_CODE) {
    if(!str_guarantee_space(tdata,MIN_STRLEN)) 
      return err_clear_detach_halt(MALLOC_ERR,tdata);
    itmp=snprintf(tdata->bufptr,MIN_STRLEN,"%lu",handlecount);    
    tdata->bufptr+=itmp;
  }
  // release locks and detach
  if (!wg_end_read(db, lock_id)) {  // release read lock
    return err_clear_detach_halt(LOCK_RELEASE_ERR,tdata);
  }
  tdata->lock_id=0;
  op_detach_database(tdata,db);
  if(!op_print_data_end(tdata,opcode==SEARCH_CODE))
    return err_clear_detach_halt(MALLOC_ERR,tdata);
  return tdata->buf;
}