/* * $Id: topicmap.c,v 1.3 2004/12/11 17:08:13 jan Exp $ * * Copyright (c) 2002 Jan Algermissen * See the file "COPYING" for copying permission. * */ #include "tm.h" #include "tmmem.h" #include "tmstack.h" #include "tmtrace.h" #include "tmutil.h" #include "tmtable.h" #include "tmtopicset.h" #include "tmstorage.h" #include "tmassert.h" /* #include "tmparams.h" */ #include "tmqlnode.h" #include "tmresult.h" #include "tmtopicmap.h" #include "tmtransaction.h" #include #include /* */ /* for bootsrapping (is loaded in open) */ /* extern struct TMModel coremodel; */ /* local tracing stuff. Should propably not depend on NDEBUG - it is adding * overhead, even if tracing is not on for TM_TOPICMAP_TRACE (FIXME) */ #ifndef NDEBUG #define TRACE_PROP_VALUE(prop,vtype,value) do { \ char buf[11024]; \ tm_value_to_string( (vtype), (value), buf,sizeof(buf)); \ TMTRACE(TM_GRAPH_TRACE,"prop value: %s%s=%s\n" _ \ (prop)->model _ (prop)->name _ buf); \ } while(0) #define TRACE_VALUE(vtype,value) do { \ char buf[11024]; \ tm_value_to_string( (vtype), (value), buf,sizeof(buf)); \ TMTRACE(TM_GRAPH_TRACE,"value: %s\n" _ buf); \ } while(0) #else #define TRACE_VALUE(prop,vtype,value) /* as nothing */ #define TRACE_PROP_VALUE(prop,vtype,value) /* as nothing */ #endif struct TMTopicMap { TM tm; int is_open; TMPool pool; TMTopicMapStorageDescriptor storage_descriptor; /* this describes the storage system */ void *storage_handle; /* generic data for storage system */ TMList models; /* currently loaded models */ TMMetaStore meta_store; /* the store for meta data */ TMList value_stores; /* all value stores */ TMList property_stores; /* all property stores */ TMTable propname_to_vstore_table; /* find store by prop's fullname */ TMTable propname_to_pstore_table; /* find store by prop's fullname */ TMStack transactions; /* stack of transactions */ TMList merge_lists; TMList new_topic_list; TMTable vnorm_table; TMTable prop_table; /* holds properties from loaded models by fullname */ }; struct TMTopicScan { int foo; char tag[TM_MAXTAG]; TMList topics; }; /* ========================================================================= * * STATIC PROTOTYPES * (definitions are at the end of this file) * * ========================================================================= */ /* * Get current transaction. */ static TMTransaction current_transaction(TMTopicMap self); /* * Lookup the model in the list of loaded models. * Return model or NULL if not found. */ static TMModel tm_topicmap_get_model_by_name(TMTopicMap self,const char *name); /* * Load a certain model into the topic map. */ static TMError _load_model(TMTopicMap self,TMModel model); /* * Get the pstore and vstore for a given property. */ static TMError _get_stores(TMTopicMap self, TMProperty prop, TMPropertyStore *pstore, TMValueStore *vstore); /* * */ static int _have_stores(TMTopicMap self, TMProperty prop, TMPropertyStore *pstore, TMValueStore *vstore); /* * Open the pstore and vstore for a given property */ static TMError _open_stores(TMTopicMap self, TMProperty prop); /* * */ static TMError _pstore_get(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, void **valp); /* * */ static TMError _topicmap_create_topic(TMTopicMap self, TMTopic *np); /* * */ static TMError tm_topicmap_add_property_to_topic(TMTopicMap self, TMTopic topic, TMProperty prop, const void *value,int vflags); /* * */ static TMError _internal_add_topic(TMTopicMap self, TMSubject subject, TMTopic *pt); /* * */ static TMError XXXXX_do(TMTopicMap self,TMProperty prop, void*value); /* * */ static TMError YYYYY_do(TMTopicMap self,TMProperty prop, void*value); /* * */ TMError _normalize_vstore(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore); /* * */ static TMList add_to_vidset_list(TMPool pool,TMList setlist,TMList vid_equ_list); /* check if all property stores are normalized static int tm_topicmap_all_stores_normalized(TMTopicMap self); */ /* print a topic and all its properties */ /* static void print_topic(TMTopicMap self,TMTopic i, FILE* file); */ /* lookup a topic by the value of an SIDP property. */ /* static TMError _lookup_topic_by_sidp(TMTopicMap self,TMProperty prop,const void *value,TMTopic *np); */ /* Lookup a property in the topicmap. Return NULL if not found. */ /* static TMProperty _lookup_property(TMTopicMap self, const char *modelname, const char* propname); */ /* static TMError _store_value(TMTopicMap self, TMValueStore vstore, const void *value, TMVid *vidp); static TMError tm_topicmap_merge_topics(TMTopicMap self,TMTopic stays, TMTopic disappears); */ /* static TMError _pstore_put(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, const void* value); */ /* static void _set_contradicting_values_error(TMTopicMap self,TMProperty prop, TMValueStore vstore,TMVid vid1,TMVid vid2); static void _set_contradicting_values_error_2(TMTopicMap self,TMProperty prop, const void*,const void*); static TMError _pstore_vput(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, const void* value, TMVid *pvid); */ /* static TMError tm_topicmap_topic_scan_open(TMTopicMap self, TMCETree cetree, const char *tag, TMTopicScan *scanp); */ static TMError _pstore_replace_topics(TMTopicMap self,TMProperty prop,TMPropertyStore pstore,TMValueStore vstore,TMTopic new_topic,TMTopicSet set); static TMError _pstore_replace_topics_in_values(TMTopicMap self,TMProperty prop,TMPropertyStore pstore,TMValueStore vstore,TMTopic new_topic,TMTopicSet set); static void set_vstore_normalized_state(TMTopicMap self, const char *fullname, int b); static int vstore_is_normalized(TMTopicMap self, const char *fullname); static TMError tm_topicmap_copy_topic(TMTopicMap self,TMTopic topic, TMTopicMap other); static TMError _make_subject(TMTopicMap self,TMSubject sbj); /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMTopicMap tm_topicmap_new(TMPool pool,TM tm) { TMTopicMap self; TMPool mypool; mypool = tm_pool_new("topicmap-pool",pool); TM_NEW(mypool,self); self->is_open = 0; self->tm = tm; self->pool = mypool; self->storage_descriptor = NULL; self->storage_handle = NULL; self->models = NULL; self->prop_table = tm_table_new(mypool,100,tm_strcmp_v,tm_strhash_v); self->meta_store = NULL; self->value_stores = NULL; self->property_stores = NULL; self->propname_to_vstore_table = tm_table_new(mypool,100,tm_strcmp_v,tm_strhash_v); self->propname_to_pstore_table = tm_table_new(mypool,100,tm_strcmp_v,tm_strhash_v); self->transactions = tm_stack_new(mypool,0); self->merge_lists = NULL; self->new_topic_list = NULL; self->vnorm_table = tm_table_new(mypool,10,tm_strcmp_v,tm_strhash_v); TM_LOG(self->tm,TM_LOG_INFO,"[tm] created"); return self; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_set_storage(TMTopicMap self,const char *storage_name) { assert(self); assert(!self->is_open); self->storage_descriptor = tm_lookup_storage_descriptor(self->tm,storage_name); if(! self->storage_descriptor) return TM_FAIL; TM_LOG(self->tm,TM_LOG_INFO,"[tm] using storage: %s" _ storage_name ); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ void tm_topicmap_delete(TMTopicMap *pself) { TMTopicMap self; TM tm; TMPool pool; assert(pself && *pself); self = *pself; assert(!self->is_open); tm = self->tm; pool = self->pool; tm_list_delete(pool,&self->models); tm_table_delete(&self->prop_table); tm_table_delete(&self->propname_to_vstore_table); tm_table_delete(&self->propname_to_pstore_table); tm_table_delete(&self->vnorm_table); tm_stack_delete(&self->transactions); /* fixme: merge lists TMList !! */ TM_FREE(pool,self); tm_pool_delete(&pool); TM_LOG(tm,TM_LOG_INFO,"[tm] destroyed"); } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_open(TMTopicMap self,void* args) { TMError e; #if 0 not needed in memstore TMList model_list,lp; /* for loading the models */ #endif assert(self); assert(!self->is_open); TMTRACE(TM_GRAPH_TRACE,"enter\n"); TM_LOG(self->tm,TM_LOG_INFO,"[tm] opening"); /* it's caller's responsibility to set storage first */ assert(self->storage_descriptor); /* Handle storage arguments (e.g. path or DB access info). This * might for example involve copying or converting to a table. * Considering DB access, the connection would also be made there. */ if( (e = self->storage_descriptor->init_store(self->pool,self->tm,args,&self->storage_handle)) != TM_OK) { /* error has been set in init_store() */ return e; } self->meta_store = tm_meta_store_new(self->storage_descriptor,self->storage_handle); assert(self->meta_store); if( (e = tm_meta_store_open(self->meta_store)) != TM_OK) { /* FIXME cleanup of all the above */ return e; } /* load all basic props here */ #if 0 if( (e = _load_model(self,&coremodel)) != TM_OK) return e; #endif /* make function to load property */ #if 0 not needed with memstore. Beware: there are pool responsibility issues with the list. Either pass our pool in or make iterator. (FIXME) /* Now we need to load all the models that are known to * be required for this topicmap. */ tm_meta_store_get_model_list(self->meta_store,&model_list); for(lp=model_list;lp;lp=lp->next) { assert(0); TMTRACE(TM_GRAPH_TRACE,"from metastore: model: %s\n" _ (const char*)lp->content); /* FIXME: require would again store in store via _load_model, eh? */ if( (e = tm_topicmap_require_model(self,(const char*)lp->content)) != TM_OK) return e; } tm_list_delete(self->pool,&model_list); #endif self->is_open = 1; TM_LOG(self->tm,TM_LOG_INFO,"[tm] opened"); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_close(TMTopicMap self) { TMList lp; assert(self); assert(self->is_open); /* FIXME !! assert(tm_stack_size(self->transactions) == 0); */ TM_LOG(self->tm,TM_LOG_INFO,"[tm] closing"); /* We are closing and deleting stores here, since if topicmap * is closed, we want no store open any more. If no store is * open we don't want them allocated. * FIXME: what about reopening? */ for(lp=self->value_stores;lp;lp=lp->next) { /* tm_value_store_print(lp->content,stderr); */ tm_value_store_close((TMValueStore)lp->content); /* close the value store */ tm_value_store_delete((TMValueStore)lp->content); } for(lp=self->property_stores;lp;lp=lp->next) { /* tm_property_store_print(lp->content,stderr); */ tm_property_store_close((TMPropertyStore)lp->content); /* close the property store */ tm_property_store_delete((TMPropertyStore)lp->content); } /* since topicmaps are deleted, lists are useless */ tm_list_delete(self->pool,&self->value_stores); tm_list_delete(self->pool,&self->property_stores); /* FIXME!!!! remove all from tables and also delete list * of loaded models!! */ tm_meta_store_close(self->meta_store); tm_meta_store_delete(self->meta_store); /* Do any required cleanup on the storage args, that might * involve deallocation for example. */ self->storage_descriptor->cleanup_store(self->storage_handle); self->is_open = 0; TM_LOG(self->tm,TM_LOG_INFO,"[tm] closed"); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_require_model(TMTopicMap self,TMModel model) { TMError e; TMList rmp; assert(self); assert(self->is_open); TMTRACE(TM_GRAPH_TRACE,"enter, model=%s\n" _ model->name); /* Do we have it already? */ if( tm_topicmap_get_model_by_name(self,model->name) != NULL) return TM_OK; /* A Model may require other models, so we need to make * sure they are present. */ for(rmp = model->require; rmp; rmp=rmp->next) { TMModel rm; TMTRACE(TM_GRAPH_TRACE, "%s requires %s\n" _ model->name _ (char*)rmp->content); if( (e = tm_lookup_model(self->tm, (char*)rmp->content,&rm)) != TM_OK) return e; if( (e = tm_topicmap_require_model(self,rm)) != TM_OK) return e; } if( (e = _load_model(self,model)) != TM_OK) return e; /* make persistent in garph */ TMTRACE(TM_GRAPH_TRACE,"now adding model %s in metastore\n" _ model->name); if( (e=tm_meta_store_add_model(self->meta_store,model->name)) != TM_OK) return e; return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_get_models(TMTopicMap self,TMList *listp) { TMList list = NULL,lp; assert(self); for(lp = self->models; lp; lp=lp->next) list = tm_list_push(tm_topicmap_get_current_transaction_pool(self),list,(TMModel)lp->content); *listp = list; return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ void tm_topicmap_dump(TMTopicMap self, FILE *file) { TMList lp; TMTopic i,max; assert(self); assert(file); fprintf(file,"[Topic Map Dump]\n\n\n"); assert(self); fprintf(file,"[Models]\n"); for(lp = self->models; lp; lp=lp->next) { TMModel model = (TMModel)lp->content; fprintf(file,"%s\n",model->name ); } /*--------*/ fprintf(file,"Special Section: Value Stores\n"); fprintf(file,"=======================================================\n"); for(lp = self->value_stores; lp; lp=lp->next) { tm_value_store_print((TMValueStore)lp->content,file); } fprintf(file,"=======================================================\n"); /*--------*/ for(lp = self->property_stores; lp; lp=lp->next) { tm_property_store_print((TMPropertyStore)lp->content,file); } #if 0 fprintf(file,"\n[Unprocessed Merge List]\n"); for(lp = self->merge_lists; lp; lp=lp->next) { TMTopicSet set = (TMTopicSet)lp->content; tm_topicset_print(set,file); fprintf(file,"\n"); } #endif fprintf(file,"\n[Topic with properties]\n"); tm_meta_store_get_topicmax(self->meta_store,&max); for(i=1;i<=max;i++) { TMList mp; int topic_printed = 0; for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; for(pp=m->properties; pp; pp=pp->next) { void *value; char buf[4096]; TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; if( (e = _pstore_get(self,prop,pstore,vstore,i,&value)) != TM_OK) return; /* FIXME */ if(!value) continue; tm_value_to_string(prop->value_type,value,buf,sizeof(buf)); if(!topic_printed) { /* fprintf(file,"#%06d { %-20s : %s",i,prop->fullname,buf); */ fprintf(file,"#%06d { %s : %s",i,prop->fullname,buf); topic_printed = 1; } else { /* fprintf(file," %-20s : %s", prop->fullname,buf); */ fprintf(file,",%s : %s", prop->fullname,buf); } tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&value); } } if(topic_printed) { /* assert(self->disposed[i] == 0); */ fprintf(file," }\n"); /* char tbuf[4096]; tm_topicmap_get_sidp_string(self,i,tbuf,4096); fprintf(file,"%s\n", tbuf); */ } else { /* assert(self->disposed[i] == 1); */ fprintf(file,"#%06d *** DISPOSED ***\n",i); } } } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TM tm_topicmap_get_tm(TMTopicMap self) { assert(self); return self->tm; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_start_transaction(TMTopicMap self, const char *tag) { TMTransaction t; assert(self); assert(self->is_open); t = tm_transaction_new(self->pool,self->tm,tag); tm_stack_push(self->transactions,t); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] started" _ tag); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_end_transaction(TMTopicMap self) { TMTransaction t; assert(self); assert(self->is_open); assert(tm_stack_size(self->transactions) > 0); t = (TMTransaction)tm_stack_top(self->transactions); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] committing" _ tm_transaction_get_tag(t) ); #if 0 if( (e = tm_topicmap_fully_merge(self)) != TM_OK) { /* FIXME: rollback here? */ assert(0); return e; } #endif t = (TMTransaction)tm_stack_pop(self->transactions); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] committed" _ tm_transaction_get_tag(t) ); tm_transaction_delete(&t); /* FIXME: free symbol table */ return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_rollback_transaction(TMTopicMap self) { TMTransaction t; assert(self); assert(self->is_open); assert(tm_stack_size(self->transactions) > 0); t = (TMTransaction)tm_stack_pop(self->transactions); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] rolling back" _ tm_transaction_get_tag(t) ); tm_transaction_delete(&t); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMPool tm_topicmap_get_current_transaction_pool(TMTopicMap self) { TMTransaction tx; TMPool pool; assert(tm_stack_size(self->transactions) > 0); tx = current_transaction(self); pool = tm_transaction_get_pool(tx); TM_RETURN(pool); } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_get_property(TMTopicMap self, TMTopic topic, TMProperty prop, void **valuep) { TMError e; TMPropertyStore pstore; TMValueStore vstore; assert(self); assert(topic); assert(valuep); *valuep = NULL; TMTRACE(TM_GRAPH_TRACE, "enter prop=%s\n" _ prop->fullname); if(tm_topicmap_get_property_by_name(self,prop->fullname) == NULL) return(TM_OK); _get_stores(self,prop,&pstore,&vstore); if( (e = _pstore_get(self,prop, pstore,vstore,topic,valuep)) != TM_OK) { return e; } TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMProperty tm_topicmap_get_property_by_name(TMTopicMap self, const char *fullname) { TMProperty prop; TM_ENTER; TMTRACE(TM_GRAPH_TRACE, "fullname=_%s_\n" _ fullname); prop = (TMProperty)tm_table_get(self->prop_table,fullname); TMTRACE(TM_GRAPH_TRACE, "prop=%s\n" _ prop ? prop->fullname : "not-found" ); TM_RETURN(prop); } /* ------------------------------------------------------------------------- * * * * ------------------------------------------------------------------------- */ TMError tm_topicmap_add_topic(TMTopicMap self, TMSubject subject, const char *symbol) { TMError e; TMTopic topic; TM_ENTER; assert(self); assert(subject); assert(subject->topic == 0); if( (e = _internal_add_topic(self,subject,&topic)) != TM_OK) return e; if(symbol) { TMTransaction tx; tx = current_transaction(self); tm_transaction_store_topic(tx,symbol,topic); } TM_RETURN(TM_OK); } #if 0 TMError tm_topicmap_fully_merge2(TMTopicMap self) { TMList mp,lp; int count = 0; TMError e; assert(0); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] starting a full merge2" _ tm_transaction_get_tag(current_transaction(self)) ); assert(self->is_open); while( ! tm_topicmap_all_stores_normalized(self)) { TMTRACE(TM_GRAPH_TRACE,"============================||\n"); assert(self->merge_lists == NULL); /* normalize property stores => produce a list of merge_sets */ for(lp=self->property_stores;lp;lp=lp->next) { TMPropertyStore pstore = (TMPropertyStore)lp->content; /* need to pass ourselves, because store needs to add mergelists to us! */ e = tm_property_store_normalize(pstore,self,NULL,NULL); assert(e == TM_OK); /*FIXME */ } /* now we have a bunch of disjoint merge sets that need to be processed */ TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s] pstores normalized" _ tm_transaction_get_tag(current_transaction(self)) ); /* substitute all topics in property stores */ for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; TMTRACE(TM_GRAPH_TRACE,"replace topics loop for model %s\n" _ m->name); for(pp=m->properties; pp; pp=pp->next) { TMList kp; TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; for(kp = self->merge_lists; kp; kp=kp->next) { if( (e = _pstore_replace_topics(self,prop,pstore,vstore, (TMTopicSet)kp->content)) != TM_OK) return e; } } } /* fails - why? assert(tm_topicmap_all_stores_normalized(self)); */ /* now al stores are normalized (except for topics in values!) */ for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; TMTRACE(TM_GRAPH_TRACE,"replace topics in values loop for model %s\n" _ m->name); for(pp=m->properties; pp; pp=pp->next) { TMList kp; TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; for(kp = self->merge_lists; kp; kp=kp->next) { if( (e = _pstore_replace_topics_in_values(self,prop,pstore,vstore, (TMTopicSet)kp->content)) != TM_OK) return e; } } } /* now cleanup saved_merge_lists */ for(lp = self->merge_lists; lp; lp=lp->next) { int len,i; TMTopicSet set = (TMTopicSet)lp->content; len = tm_topicset_size(set); /* first is 'stays', so we start at index 1 */ for(i=1;imerge_lists)); self->merge_lists = NULL; /* FIXME: free list and sets (is now done, or?)! */ /* avoid endless loop in any case */ if(++count > 200) { assert(0); /* make sure we catch this (impossible?) event during development! */ break; } } /* while not all stores normalized */ return TM_OK; } /fully merge2 #endif TMError _pstore_replace_topics(TMTopicMap self,TMProperty prop,TMPropertyStore pstore,TMValueStore vstore,TMTopic new_topic,TMTopicSet set) { int i,len; TMError e; TMVid comb_vid; void *comb_val = NULL; TMPool pool = tm_topicmap_get_current_transaction_pool(self); TMTable vidtab = tm_table_new(pool,10,NULL,NULL); TMList vp,vids; TMTRACE(TM_GRAPH_TRACE,"enter [prop=%s][New: %d]\n" _ prop->fullname _ new_topic ); len = tm_topicset_size(set); TMTRACE(TM_GRAPH_TRACE,"MergeSet is [ "); for(i=0;ifullname); TMTRACE(TM_GRAPH_TRACE,"begin vidlist ========================================\n"); { TMList lp; for(lp=vids;lp;lp=lp->next) TMTRACE(TM_GRAPH_TRACE,"VID: %d\n" _ (TMVid)lp->content); } TMTRACE(TM_GRAPH_TRACE,"end vidlist=========================================\n"); if(vids == NULL) { TMTRACE(TM_GRAPH_TRACE,"none of topicset in this pstore"); tm_list_delete(pool,&vids); tm_table_delete(&vidtab); TM_RETURN(TM_OK); } TMTRACE(TM_X_TRACE,"A01\n"); if(vids->next == NULL) /* size == 1? */ { TMList tlist,tp; TMTRACE(TM_X_TRACE,"A02 (all topics have same VID, no val merge needed)\n"); vp = vids; tlist = tm_table_get(vidtab,vp->content); if( (e = tm_property_store_insert(pstore,new_topic,(TMVid)vp->content)) != TM_OK) TM_RETURN(e); for(tp=tlist;tp;tp=tp->next) { if( (e = tm_property_store_remove(pstore,(TMTopic)tp->content)) != TM_OK) return e; } tm_list_delete(pool,&tlist); /* that was the only list, no need to free any other */ tm_table_delete(&vidtab); tm_list_delete(pool,&vids); TM_RETURN(TM_OK); } TMTRACE(TM_GRAPH_TRACE, "got diverse VIDs for topics in mergeset, need val combi\n"); /* need to combine values */ if(! prop->combination_code) { TMTRACE(TM_GRAPH_TRACE, "no combination code in prop\n"); if(! tm_valuetype_parse_opstring(prop->value_type,"VALUE_INCLUDES_TOPIC")) { /* _set_contradicting_values_error_2(self,prop,value,exist_val); */ /* _set_contradicting_values_error(self,prop,vstore,stays_vid,disap_vid); */ assert(0); return TM_ECONTRADICTING_PROPERTY_VALUES; } /* if values may contain topics, we assume error is due to * unknown future equivalence of topics and just proceed. * FIXME: this can be made better by providing an equality check * by the vtype that explcitly checks for topic-inequality * situations. */ /* print_topic(self,stays,stderr); print_topic(self,disap,stderr); getchar(); */ /* if( (e = tm_property_store_remove(pstore,disap)) != TM_OK) return e; */ /* do nothing else */ /*assert(0); *//* what to do? for each topic? */ assert(0); return(0); } TMTRACE(TM_X_TRACE,"A03"); for(vp=vids;vp;vp=vp->next) { void *val; TMList tlist,tp; TMVid vid = (TMVid)vp->content; if( (e = tm_value_store_get_value(vstore,vid,pool,&val)) != TM_OK) TM_RETURN(e); if(!comb_val) { TMTRACE(TM_GRAPH_TRACE, "comb still null, assigning other\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,val); comb_val = val; } else { TMTRACE(TM_GRAPH_TRACE, "current comb\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,comb_val); TMTRACE(TM_GRAPH_TRACE, "other value\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,val); TMTRACE(TM_GRAPH_TRACE, "now combining values and storing result as prop val\n"); comb_val = tm_value_call(prop->value_type,comb_val,prop->combination_code,pool,val); TMTRACE(TM_GRAPH_TRACE, "now comb:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,comb_val); tm_value_delete(pool,prop->value_type,&val); /* */ } TMTRACE(TM_X_TRACE,"A05"); tlist = tm_table_get(vidtab,(void*)vp->content); for(tp=tlist;tp;tp=tp->next) { if( (e = tm_property_store_remove(pstore,(TMTopic)tp->content)) != TM_OK) return e; } tm_list_delete(pool,&tlist); } TMTRACE(TM_X_TRACE,"A04"); tm_list_delete(pool,&vids); tm_table_delete(&vidtab); if( (e = tm_value_store_lookup_vid(vstore,comb_val,0,TM_VALUE_LOOKUP_OR_CREATE,&comb_vid)) != TM_OK) TM_RETURN(e); if( (e = tm_property_store_insert(pstore,new_topic,comb_vid)) != TM_OK) TM_RETURN(e); tm_value_delete(pool,prop->value_type,&comb_val); TMTRACE(TM_X_TRACE,"A06"); TM_RETURN(TM_OK); #if 0 for(i=1;i combine\n"); if(! prop->combination_code) { TMTRACE(TM_GRAPH_TRACE, "no combination code in prop\n"); if(! tm_valuetype_parse_opstring(prop->value_type,"VALUE_INCLUDES_TOPIC")) { /* _set_contradicting_values_error_2(self,prop,value,exist_val); */ _set_contradicting_values_error(self,prop,vstore,stays_vid,disap_vid); return TM_ECONTRADICTING_PROPERTY_VALUES; } /* if values may contain topics, we assume error is due to * unknown future equivalence of topics and just proceed. * FIXME: this can be made better by providing an equality check * by the vtype that explcitly checks for topic-inequality * situations. */ /* print_topic(self,stays,stderr); print_topic(self,disap,stderr); getchar(); */ /* */ if( (e = tm_property_store_remove(pstore,disap)) != TM_OK) return e; /* do nothing else */ continue; } if( (e = tm_value_store_get_value(vstore,stays_vid, tm_topicmap_get_current_transaction_pool(self),&stays_val)) != TM_OK) return e; if( (e = tm_value_store_get_value(vstore,disap_vid, tm_topicmap_get_current_transaction_pool(self),&disap_val)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "stays value:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,stays_val); TMTRACE(TM_GRAPH_TRACE, "disap value:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,disap_val); TMTRACE(TM_GRAPH_TRACE, "now combining values and storing result as prop val\n"); comb_val = tm_value_call(prop->value_type,stays_val,prop->combination_code, tm_topicmap_get_current_transaction_pool(self),disap_val); TMTRACE(TM_GRAPH_TRACE, "comb value:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,comb_val); /* remove since we re-store it with combined property */ if( (e = tm_property_store_remove(pstore,stays)) != TM_OK) return e; if( (e = tm_property_store_remove(pstore,disap)) != TM_OK) return e; if( (e = _pstore_vput(self,prop,pstore,vstore,comb_val,&comb_vid)) != TM_OK) return e; if( (e = tm_property_store_insert(pstore,stays,comb_vid)) != TM_OK) return e; stays_vid = comb_vid; /* FIXME yes or no? tm_value_delete(prop->value_type,&exist_val); tm_value_delete(prop->value_type,&comb_val); */ } TMTRACE(TM_GRAPH_TRACE,"exit\n"); #endif return TM_OK; } TMError _pstore_replace_topics_in_values(TMTopicMap self,TMProperty prop,TMPropertyStore pstore,TMValueStore vstore,TMTopic new_topic,TMTopicSet set) { int i,len; TMError e; TMValueStoreScan vscan; TMList vp,vids = NULL; int opcode; TMTRACE(TM_GRAPH_TRACE,"enter for prop=%s" _ prop->fullname); opcode = tm_valuetype_parse_opstring(prop->value_type,"VALUE_INCLUDES_TOPIC"); if(!opcode) return TM_OK; len = tm_topicset_size(set); TMTRACE(TM_GRAPH_TRACE,"repl. values in topics, MergeSet is [ "); for(i=0;inext) { if( (TMVid)lp->content == vid) { found = 1; break; } } if(!found) { /* get value, substitute, remove old and vput new one etc. */ /* later on, see if we can have a merge or if w just have new topic lists (just that store isn;t normalized anymore!...*/ vids = tm_list_push(tm_topicmap_get_current_transaction_pool(self),vids,(void*)vid); } } /* while vscan has more */ if( (e = tm_value_store_scan_close(vstore,vscan)) != TM_OK) return e; } /* for each topic in merge set */ for(vp=vids;vp;vp=vp->next) { TMTopic *topics; TMList lp,saved_topics = NULL; /* we must not alter store while using 'topics' */ int i,len; int changed; void *v; TMVid new_vid; TMVid vid = (TMVid)vp->content; TMTRACE(TM_GRAPH_TRACE,"vid=%d has one of mergeset\n" _ vid); if( (e = tm_value_store_get_value(vstore,vid,tm_topicmap_get_current_transaction_pool(self),&v)) != TM_OK) return e; TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,v); changed = (int)tm_value_call(prop->value_type , v , "replaceTopics" ,new_topic,set); assert(changed); TMTRACE(TM_GRAPH_TRACE,"New value (with topics replaced)\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,v); if( (e = tm_value_store_lookup_vid(vstore,v,0, TM_VALUE_LOOKUP_OR_CREATE,&new_vid)) != TM_OK) { assert(0); return e; } tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&v); TMTRACE(TM_GRAPH_TRACE,"Value with replaced topics has new vid=%d (old was %d)\n" _ new_vid _ vid); if( (e = tm_property_store_lookup_topics(pstore,vid,&topics,&len)) != TM_OK) return e; for(i=0;inext) { if( (e = tm_property_store_remove(pstore,(TMTopic)lp->content)) != TM_OK) return e; } for(lp=saved_topics;lp;lp=lp->next) { if( (e = tm_property_store_insert(pstore,(TMTopic)lp->content,new_vid)) != TM_OK) return e; } tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&saved_topics); } tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&vids); return TM_OK; } TMError tm_topicmap_lookup_topic_by_subject(TMTopicMap self, TMSubject subject, TMTopic *np) { TMError e; int i; assert(self); assert(subject); assert(np); TM_ENTER; *np = 0; for(i=0; iN;i++) { TMPropertyStore pstore; TMValueStore vstore; TMVid vid; TMTopic *topics; int len; if(subject->props[i].prop->type != TM_SIDP) continue; if(! _have_stores(self,subject->props[i].prop,&pstore,&vstore)) continue; if( (e = tm_value_store_lookup_vid(vstore, subject->props[i].value,0,TM_VALUE_LOOKUP,&vid)) != TM_OK) TM_RETURN(e); if(!vid) continue; if( (e = tm_property_store_lookup_topics(pstore,vid,&topics,&len)) != TM_OK) TM_RETURN(e); if(len == 0) continue; assert(len == 1); /* FIXME: ambigous not allowed */ *np = topics[0]; break; /* one match enough, but maybe prevent ambigous lookup later?? */ } TM_RETURN(TM_OK); } #if 0 /* revised 1. Apr 2003 */ TMError tm_topicmap_xml_export(TMTopicMap self, FILE *f) { #if 0 TMTopic topicmax,topic; TMList lp; assert(self); assert(f); fprintf(f,"\n"); fprintf(f,"\n"); fprintf(f,"\n"); for(lp=self->models;lp;lp=lp->next) { fprintf(f," %s\n", ((TMModel)lp->content)->name ); } fprintf(f,"\n"); tm_meta_store_get_topicmax(self->meta_store,&topicmax) ; for(topic = 1; topic <= topicmax; topic++) { TMList lp; fprintf(f,"\n",topic); for(lp=self->property_stores;lp;lp=lp->next) { const void *value; TMError e; char buf[132000]; TMVid vid = 0; TMValueStore vstore; TMValueType vtype; TMProperty prop; TMPropertyStore pstore = (TMPropertyStore)lp->content; /* prop = tm_property_store_get_property(pstore); */ vtype = prop->value_type; vstore = (TMValueStore)tm_table_get( self->propname_to_vstore_table,prop->name); assert(vstore); /* if prop is there,store must too */ if( (e = tm_property_store_lookup_vid(pstore,topic, &vid)) != TM_OK) return e; if(!vid) continue; tm_value_store_get_value(vstore,vid,tm_topicmap_get_current_transaction_pool(self),&value); tm_value_to_xml(vtype,value, buf,sizeof(buf)); fprintf(f, " \n%s\n \n", prop->model,prop->name,vtype->name,vid,buf); tm_value_delete( vtype, &value); } fprintf(f,"\n"); } /* This must be done with the TMM defined props */ fprintf(f,"\n"); #endif return TM_OK; } /* NEW */ /*----------------------------------------------------------------------- * * *----------------------------------------------------------------------- */ /* NEW, ok 02 Sep 2003 */ #if 0 STEVE /* NEW */ TMError _pstore_put(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, const void* value) { TMVid vid; TMVid exist_vid; TMError e; void *exist_val; void *comb_val; TMVid comb_vid; TMTRACE(TM_GRAPH_TRACE, "enter\n"); /* we used to vput here, but that does not work,because in case exist_vid, * vputted value is hard to remove again! */ if( (e = tm_property_store_get_vid_of_topic(pstore,topic,&exist_vid)) != TM_OK) return e; if(! exist_vid) { /* topic not yet in store */ if( (e = _pstore_vput(self,prop,pstore,vstore,value,&vid)) != TM_OK) return e; if( (e = tm_property_store_insert(pstore,topic,vid)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } /* topic is already in store */ TMTRACE(TM_GRAPH_TRACE, "topic has already a value for this property\n"); if( (e = tm_value_store_get_value(vstore,exist_vid,tm_topicmap_get_current_transaction_pool(self),&exist_val)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "existing value:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,exist_val); /* same prop value assigned twice? */ /* FIXME: maybe a vstore can later on implement equality check between value and * a vid to avoid fetching the exist_val? */ if(tm_value_equal(prop->value_type,exist_val,value)) { TMTRACE(TM_GRAPH_TRACE, "same value assigned twice (that is ok)\n"); tm_value_delete(prop->value_type,&exist_val); return TM_OK; } TMTRACE(TM_GRAPH_TRACE, "values not equal, need to combine them\n"); if(! prop->combination_code) { TMTRACE(TM_GRAPH_TRACE, "no combination code in prop -> error\n"); _set_contradicting_values_error_2(self,prop,value,exist_val); /* _set_contradicting_values_error(self,prop,vstore,vid,exist_vid); */ return TM_ECONTRADICTING_PROPERTY_VALUES; } TMTRACE(TM_GRAPH_TRACE, "now combining values and storing result as prop val\n"); /* FIXME (here could/should? be real code execution! */ comb_val = tm_value_call(prop->value_type,exist_val,prop->combination_code,value); /***************************************************** * FIXME: just some thoughts to improve speed! * -- this is how execution in value store might look like if( (e = tm_value_store_execute_combination_code(vstore,prop->combination_code, vid,existing_vid,&comb_val)) != TM_OK) return e; if(! comb_val) { _set_contradicting_values_error(self,prop,vstore,vid,exist_vid); return TM_ECONTRADICTING_PROPERTY_VALUES; } HAUPTFRAGE: was ist mit dem loesechen der anderen values....und so weiter --> ahh, the follwoing vput will handle that (partly) WICHTIG sind alle delets die ich machen muss!!! siehe Pyton code!! ***************************************************************/ /* remove since we re-store it with combined property */ if( (e = tm_property_store_remove(pstore,topic)) != TM_OK) return e; if( (e = _pstore_vput(self,prop,pstore,vstore,comb_val,&comb_vid)) != TM_OK) return e; if( (e = tm_property_store_insert(pstore,topic,comb_vid)) != TM_OK) return e; /* FIXME yes or no? tm_value_delete(prop->value_type,&exist_val); tm_value_delete(prop->value_type,&comb_val); */ TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } /* XXXX */ TMError _pstore_put(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, const void* value) { TMVid vid; TMVid exist_vid; TMError e; void *exist_val; void *comb_val; TMVid comb_vid; TMTRACE(TM_GRAPH_TRACE, "enter\n"); /* we used to vput here, but that does not work,because in case exist_vid, * vputted value is hard to remove again! */ /* if( (e = tm_property_store_get_vid_of_topic(pstore,topic,&exist_vid)) != TM_OK) return e; assert(! exist_vid) */ if( (e = tm_value_store_lookup_vid(vstore,value,0, TM_VALUE_LOOKUP_OR_CREATE,&vid)) != TM_OK) { assert(0); return e; } if( (e = tm_property_store_insert(pstore,topic,vid)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; return TM_OK; } #endif /* what if scan runs more props? * SELECT WHERE SAM/SubectData MATCHES "water AND purification" AND DC/Author = "Sam Hunting" * * * * * * */ /* NEW */ /* FIXME: is not used... why? */ TMError _pstore_normalize(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, const void* value) { TMError e; if(prop->type != TM_SIDP) return TM_OK; /* redundant */ if(tm_property_store_is_normalized(pstore)) return TM_OK; if( (e = tm_property_store_normalize(pstore,self)) != TM_OK) return e; return TM_OK; } /* --------------------- END pstore local methods ----------------------*/ /* NEW */ /* revised 07 Mar 2003 */ TMError tm_topicmap_lookup_topic_by_property(TMTopicMap self, const char *modelname, const char *propname, const void *value, TMTopic *np) { TMError e; TMProperty prop; assert(self); assert(modelname); assert(propname); assert(value); assert(np); assert(0); *np = TM_NO_NODE; TMTRACE(TM_GRAPH_TRACE, "enter\n"); prop = _lookup_property(self,modelname,propname ); if (!prop) return TM_OK; if(prop->type != TM_SIDP) return TM_E_SIDP_EXPECTED; if( (e = _lookup_topic_by_sidp(self,prop,value,np)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } TMError tm_topicmap_get_topic_from_string(TMTopicMap self, const char *modelname, const char *propname, const char *value_string, TMTopic *np, TMProperty *pp) { void *value; TMProperty prop; TMModel model; assert(np); *np = 0; /* did caller supply TMProperty pointer? => initialize */ if(pp) *pp = NULL; TMTRACE(TM_GRAPH_TRACE, "enter model=%s prop=%s\n" _ modelname _ propname); if( (model = tm_topicmap_get_model_by_name(self,modelname)) == NULL) return TM_OK; /* model absence is ok on get_topic() */ /* FIXME propably report error if asked for non-loaded prop model */ if( (prop = tm_model_get_property(model,propname)) == NULL) return TM_OK; if(pp) *pp = prop; TMTRACE(TM_GRAPH_TRACE, "value string: _%s_" _ value_string); value = tm_value_new_from_string(prop->value_type,value_string); assert(value); return (tm_topicmap_get_topic(self,modelname,propname,value,np,pp)) ; } /* NEW, ok 3.8.2003 FIXME: ambigos lookup !*/ TMError tm_topicmap_get_topic(TMTopicMap self, const char *modelname, const char *propname, const void *value, TMTopic *np, TMProperty *pp) { TMError e; TMModel model; TMProperty prop; TMPropertyStore pstore; TMValueStore vstore; TMVid vid; const char corename[] = "RM-Core"; assert(self); assert(propname); assert(value); assert(np); if(!modelname || !*modelname) { modelname = corename; } *np = 0; /* did caller supply TMProperty pointer? => initialize */ if(pp) *pp = NULL; TMTRACE(TM_GRAPH_TRACE, "enter model=%s prop=%s\n" _ modelname _ propname); if( (model = tm_topicmap_get_model_by_name(self,modelname)) == NULL) return TM_OK; /* model absence is ok on get_topic() */ /* FIXME propably report error if asked for non-loaded prop model */ if( (prop = tm_model_get_property(model,propname)) == NULL) return TM_OK; if(pp) *pp = prop; if(prop->type != TM_SIDP) { tm_set_error(self->tm,"%s is not an SIDP, lookup is impossible", prop->fullname); return TM_E_SIDP_EXPECTED; } TMTRACE(TM_GRAPH_TRACE, "value: "); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,value); _get_stores(self,prop,&pstore,&vstore); if(! tm_property_store_is_normalized(pstore)) { tm_set_error(self->tm,"%s not normalized in call to get_topic()", prop->fullname); return TM_E_PSTORE_NOT_NORMALIZED; } if( ! prop->equality_code ) /* prop NOT defines own equality */ { if( (e = tm_value_store_lookup_vid(vstore,value,0,TM_VALUE_LOOKUP,&vid)) != TM_OK) return e; } else { TMError e; int opcode; TMValueStoreScan vscan; /* get opcode from operator string in TMA definition */ opcode = tm_valuetype_parse_opstring(prop->value_type, prop->equality_code); if(!opcode) { tm_set_error(self->tm, "operator '%s' not defined for valuetype '%s'", prop->equality_code, prop->value_type->name); return TM_E_OP_UNDEFINED; } /* no argstring parsing needed, arg is value (Vq) */ if( (e = tm_value_store_scan_open(vstore, tm_topicmap_get_current_transaction_pool(self),opcode, value , &vscan )) != TM_OK) return e; if( tm_value_store_scan_finished(vstore,vscan) ) { if( (e = tm_value_store_scan_close(vstore,vscan)) != TM_OK) return e; /* not found (topic already set to 0, simply return) */ return TM_OK; } tm_value_store_scan_fetch(vstore,vscan,&vid); if(! tm_value_store_scan_finished(vstore,vscan) ) { if( (e = tm_value_store_scan_close(vstore,vscan)) != TM_OK) return e; tm_set_error(self->tm, "ambigous lookup for property value"); /* FIXME: message! */ return TM_E_AMBIGUOUS_LOOKUP; } if( (e = tm_value_store_scan_close(vstore,vscan)) != TM_OK) return e; } if( ! vid) return TM_OK; if( (e = tm_property_store_lookup_topic(pstore,vid,np)) != TM_OK) { return e; } return TM_OK; } /* revised 7 Mar 2003 */ TMError tm_topicmap_lookup_topics_by_property(TMTopicMap self, const char *modelname, const char *propname, const void *value, int flag, TMTopicSet topicset) { TMError e; TMProperty prop; TMValueType vtype; TMValueStore vstore; TMPropertyStore pstore; assert(self); assert(modelname); assert(propname); assert(value); assert(topicset); assert(0); TMTRACE(TM_GRAPH_TRACE, "enter\n"); prop = _lookup_property(self,modelname,propname); if (!prop) return TM_OK; /* --FIXME-- pstore = _get_propertystore(self,prop->model,prop->name); */ assert(pstore); /* if prop is in topicmap, store must be too */ vtype = tm_property_get_valuetype(prop); vstore = (TMValueStore)tm_table_get(self->propname_to_vstore_table,prop->name); assert(vstore); /* prop in topicmap requires vstore to be there too */ if(flag == TM_LOOKUP_EQUAL) { TMVid vid; /* if( (e = tm_value_store_get_vid(vstore,value,&vid)) != TM_OK) return e; */ if(prop->type == TM_SIDP) { TMTopic topic; if( (e = tm_property_store_lookup_topic(pstore,vid, &topic)) != TM_OK) return e; if(topic) tm_topicset_add(topicset,topic); } else { TMTopic *topics; int i,len; if( (e = tm_property_store_lookup_topics(pstore,vid, &topics,&len)) != TM_OK) return e; for(i=0; itype == TM_SIDP) { int k; for(k=0; ktype == TM_SIDP); assert( _lookup_property(self,prop->model,prop->name)); /*--FIXME-- pstore = _get_propertystore(self,prop->model,prop->name); */ assert(pstore); /* if prop is in topicmap, pstore MUST be there too */ vtype = tm_property_get_valuetype(prop); TRACE_PROP_VALUE(prop,vtype,value); vstore = (TMValueStore)tm_table_get(self->propname_to_vstore_table,prop->name); assert(vstore); /* if prop in topicmap, vstore MUST be there too */ /* --FIXME-- if( (e = tm_value_store_get_vid(vstore,value,&vid)) != TM_OK) return e; if( (e = tm_property_store_lookup_topic(pstore,vid,np)) != TM_OK) return e; */ return TM_OK; } /* NEW */ TMError tm_topicmap_topic_scan_open_with_single_condition(TMTopicMap self, const char *modelname, const char *propname, const char *opstring, const char *argstring, const char *tag, TMTopicScan *scanp) { TMCETree cetree; TMModel model; TMProperty prop; int opcode; void *arg; const char corename[] = "RM-Core"; if(!modelname || !*modelname) { modelname = corename; } model = tm_topicmap_get_model_by_name(self,modelname); assert(model); prop = tm_model_get_property(model,propname); assert(prop); opcode = tm_valuetype_parse_opstring(prop->value_type, opstring); if(!opcode) { tm_set_error(self->tm, "operator '%s' not defined for valuetype '%s'", opstring, prop->value_type->name); return TM_E_OP_UNDEFINED; } arg = tm_valuetype_parse_argstring(prop->value_type, opcode, argstring); assert(arg); /* FIXME: how to report arg parse error cause ?!!! */ TM_NEW(cetree); cetree->tree_op = TM_CETREE_OP_SIMPLE_CONDITION; cetree->prop = prop; cetree->op = opcode; cetree->arg = arg; tm_topicmap_topic_scan_open(self, cetree, tag,scanp); return TM_OK; } TMError tm_topicmap_topic_scan_open_with_double_condition(TMTopicMap self, const char *modelname1, const char *propname1, const char *opstring1, const char *argstring1, const char *operator, const char *modelname2, const char *propname2, const char *opstring2, const char *argstring2, const char *tag,TMTopicScan *scanp) { TMCETree root,left,right; TMModel model1,model2; TMProperty prop1,prop2; int opcode1,opcode2; void *arg1,*arg2; const char corename[] = "RM-Core"; if(!modelname1 || !*modelname1) { modelname1 = corename; } if(!modelname2 || !*modelname2) { modelname2 = corename; } model1 = tm_topicmap_get_model_by_name(self,modelname1); assert(model1); prop1 = tm_model_get_property(model1,propname1); assert(prop1); opcode1 = tm_valuetype_parse_opstring(prop1->value_type, opstring1); if(!opcode1) { tm_set_error(self->tm, "operator '%s' not defined for valuetype '%s'", opstring1, prop1->value_type->name); return TM_E_OP_UNDEFINED; } arg1 = tm_valuetype_parse_argstring(prop1->value_type, opcode1, argstring1); assert(arg1); /* FIXME: how to report arg parse error cause ?!!! */ model2 = tm_topicmap_get_model_by_name(self,modelname2); assert(model2); prop2 = tm_model_get_property(model2,propname2); assert(prop2); opcode2 = tm_valuetype_parse_opstring(prop2->value_type, opstring2); if(!opcode2) { tm_set_error(self->tm, "operator '%s' not defined for valuetype '%s'", opstring2, prop2->value_type->name); return TM_E_OP_UNDEFINED; } arg2 = tm_valuetype_parse_argstring(prop2->value_type, opcode2, argstring2); assert(arg2); /* FIXME: how to report arg parse error cause ?!!! */ TM_NEW(self->pool,root); TM_NEW(self->pool,left); TM_NEW(self->pool,right); left->tree_op = TM_CETREE_OP_SIMPLE_CONDITION; left->prop = prop1; left->op = opcode1; left->arg = arg1; right->tree_op = TM_CETREE_OP_SIMPLE_CONDITION; right->prop = prop2; right->op = opcode2; right->arg = arg2; if( strcmp(operator,"AND") == 0) root->tree_op = TM_CETREE_OP_AND; else if( strcmp(operator,"OR") == 0) root->tree_op = TM_CETREE_OP_OR; else { assert(0); exit(1); } root->left = left; root->right = right; tm_topicmap_topic_scan_open(self, root, tag,scanp); /* FIXME: when to free tree ??? */ return TM_OK; } TMError tm_topicmap_topic_scan_open(TMTopicMap self, TMCETree cetree, const char *tag,TMTopicScan *scanp) { TMTopicScan sp; TMTopicSet set; int i,len; TM_NEW(self->pool,sp); sp->foo = 10; /* FIXME (just stuff) */ /* FIXME: boundary check! */ if(tag) { strncpy(sp->tag,tag,sizeof(sp->tag)); } else { *(sp->tag) = '\0'; } sp->topics = NULL; set = tm_topicset_new(100); /* FIXME, hint works or not?? */ TMTRACE(TM_GRAPH_TRACE,"before evaluating cetree\n"); tm_topicmap_cetree_eval(self,cetree, set); /* FIXME: error check */ TMTRACE(TM_GRAPH_TRACE,"evaluated cetree\n"); len = tm_topicset_size(set); for(i=0;itopics = tm_list_push(sp->topics,(void*)tm_topicset_get(set,i) ); *scanp = sp; TMTRACE(TM_GRAPH_TRACE,"exit\n"); return TM_OK; } TMError tm_topicmap_topic_scan_close(TMTopicMap self, TMTopicScan scan) { TM_FREE(scan); return TM_OK; } int tm_topicmap_topic_scan_finished(TMTopicMap self, TMTopicScan scan) { /* LEAK!!! need to free list!! */ return (scan->topics == NULL); } TMError tm_topicmap_topic_scan_fetch(TMTopicMap self, TMTopicScan scan, TMTopic *tp) { void *v; TMTRACE(TM_GRAPH_TRACE,"1\n"); assert(scan->topics); TMTRACE(TM_GRAPH_TRACE,"2\n"); scan->topics = tm_list_pop(scan->topics,&v); TMTRACE(TM_GRAPH_TRACE,"3\n"); *tp = (TMTopic)v; return TM_OK; } #if 0 void print_topic(TMTopicMap self,TMTopic i, FILE* file) { TMList mp; int topic_printed = 0; for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; for(pp=m->properties; pp; pp=pp->next) { void *value; char buf[4096]; TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; pstore = tm_table_get(self->propname_to_pstore_table,prop->fullname); vstore = tm_table_get(self->propname_to_vstore_table,prop->fullname); assert(pstore); assert(vstore); if( (e = _pstore_get(self,prop,pstore,vstore,i,&value)) != TM_OK) return; /* FIXME */ if(!value) continue; tm_value_to_string(prop->value_type,value,buf,sizeof(buf)); if(!topic_printed) { fprintf(file,"<%06d> %-20s : %s\n",i,prop->fullname,buf); topic_printed = 1; } else { fprintf(file," %-20s : %s\n", prop->fullname,buf); } tm_value_delete(prop->value_type,&value); } } if(topic_printed) { fprintf(file,"\n"); } } #endif #if 0 ============================================================================ /* I keep some old code so I remember it....*/ ============================================================================ GSError_T _index_data(TM_GRAPH_T topicmap,gs_topic_t topic, const char *data) { /* GS_PAGE_T topic_headpage,dpage,npage,data_headpage; GS_PAGE_T topic_headpage; */ /* int data_pnum = 0; int data_offset = 0; */ char *word; char wordbuf[256]; assert(topicmap); TMTRACE(TM_GRAPH_TRACE,"Data [%s]\n" _ data); fflush(stdout); while( gs_strtok(&data," :.~,!()[]{}%\"@#$^&*+=|?-'<> \t\r\n",wordbuf,sizeof(wordbuf)) != NULL) { char lower_word[256]; char *p; word = wordbuf; gs_tolowercase(word,lower_word,sizeof(lower_word) ); if(!*lower_word) continue; /* fprintf(stderr,"[_%s_]\n",lower_word); */ if(strstr(lower_word," ") != NULL) { TMTRACE(TM_GRAPH_TRACE,"[_%s_]\n" _ lower_word); continue; } p = lower_word; /* printf(" %s ",p); fflush(stdout); */ /* while( *p && *(p+1) && *(p+2) ) { while( strlen(p) > 2 ) { */ gs_lookup_topic_by_data(topicmap,p,GS_SCR,GS_CREATE,topic,NULL); while(0 && *p ) { TMTRACE(TM_GRAPH_TRACE,"Indexing [_%s_]\n" _ p); gs_lookup_topic_by_data(topicmap,p,GS_SCR,GS_CREATE,topic,NULL); p++; /* printf("."); fflush(stdout); */ } /* printf("\n"); fflush(stdout); */ } return TM_OK; } GSError_T gs_topicmap_build_word_index(TM_GRAPH_T g) { /* GS_PAGE_T topic_headpage,dpage,npage,data_headpage; */ GS_PAGE_T topic_headpage; gs_topic_t max,topic; /* int data_pnum = 0; int data_offset = 0; */ assert(g); g->word_index = (struct word_bucket**)GS_ALLOC(100 * sizeof(struct word_bucket*)); g->word_index_len = 0; g->word_index_size = 100; gs_storage_fetch_page(g->topics_file,&topic_headpage,1); max = gs_topicsheadpage_get_topicmax(topic_headpage); /* pagecount = gs_topicsheadpage_get_pagecount(topic_headpage); */ gs_storage_drop_page(g->topics_file,topic_headpage); for(topic = 1; topic<=max;topic++) { char data[4096]; char *word; char wordbuf[256]; const char *dp = data; /* TBD: check freelist once we implemented merging */ gs_lookup_scr_data(g,topic,data,sizeof(data)); if(! *data) continue; /* fprintf(stderr,"Node: %d, data: %s\n",topic,data); word = strtok_r(data," ",&lasts); */ while( gs_strtok(&dp," ",wordbuf,sizeof(wordbuf)) != NULL) { int k; int found = 0; char lower_word[256]; word = wordbuf; gs_tolowercase(word,lower_word,sizeof(lower_word) ); /* fprintf(stderr," %s\n",word); */ for(k=0; kword_index_len;k++) { int c; c = strcmp(g->word_index[k]->word,lower_word); if(c == 0) found = 1; if(c >= 0) break; } if(found) { g->word_index[k]->array_len++; GS_RESIZE(g->word_index[k]->array,g->word_index[k]->array_len * 4); assert(topic); g->word_index[k]->array[g->word_index[k]->array_len-1] = topic; } else { struct word_bucket *bp; if(g->word_index_len >= g->word_index_size) { g->word_index_size *= 2; GS_RESIZE(g->word_index,g->word_index_size * sizeof(struct word_bucket) ); } bp = (struct word_bucket *) GS_ALLOC(sizeof(struct word_bucket)); assert(bp); bp->array_len = 1; bp->array = (int*)GS_ALLOC(1 * sizeof(gs_topic_t)); assert(bp->array); assert(topic); bp->array[0] = topic; bp->word = (char*)GS_ALLOC(strlen(lower_word)+1); assert(bp->word); strcpy(bp->word,lower_word); /* if need to insert in between */ if(k < g->word_index_len) { int j; for(j = g->word_index_len; j > k; j--) g->word_index[j] = g->word_index[j-1]; } /* fprintf(stderr,"insert %s at pos %d\n",bp->word,k); */ g->word_index[k] = bp; g->word_index_len++; if(0) { int l; fprintf(stderr,"------------------------------------\n"); for(l = 0; l < g->word_index_len; l++) { fprintf(stderr," %5d: %s\n",l,g->word_index[l]->word); } fprintf(stderr,"------------------------------------\n"); } } } } } TMError tm_topicmap_merge(TMTopicMap self, TMTopicMap other) { assert(self); assert(other); /* - require models of other - walk all topics and test if merge with self or add keep mergelist assertions ?? */ return TM_OK; } #endif TMError tm_topicmap_clone_topic(TMTopicMap source, TMTopic topic, TMTopicMap dest, TMTopic *tp) { assert(source); assert(topic); assert(dest); if(tp) *tp = 0; assert(0); return TM_OK; } TMError tm_topicmap_get_sidp_string(TMTopicMap self, TMTopic topic, char *buf, size_t size) { TMList mp; char *p; int n; assert(self); assert(topic > 0); assert(buf); p = buf; *p = '\0'; assert(0); for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; int opcode; TMModel m = (TMModel)mp->content; for(pp=m->properties; pp; pp=pp->next) { void *value; TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(prop->type != TM_SIDP) continue; /* ??? FIXME: make property on prop! that it is a graph-conn prop */ /* also: expand topics in values */ if(strcmp(prop->name,"SourceLocators") == 0) continue; /* */ opcode = tm_valuetype_parse_opstring(prop->value_type, "VALUE_INCLUDES_TOPIC"); /* also FIXME! here we simply skip the problematic ones */ /* Reason: topics in vals make BAD sidp_strings! */ if(opcode) continue; pstore = tm_table_get(self->propname_to_pstore_table,prop->fullname); vstore = tm_table_get(self->propname_to_vstore_table,prop->fullname); assert(pstore); assert(vstore); if( (e = _pstore_get(self,prop,pstore,vstore,topic,&value)) != TM_OK) return e; /* FIXME */ if(!value) continue; n = snprintf(p,size,"%s%s===", m->name, prop->name); size -= n; p += n; tm_value_to_string(prop->value_type,value,p,size); n = strlen(p); size -= n; p += n; sprintf(p,"%s","|||"); size -= 3; p += 3; tm_value_delete(prop->value_type,&value); } } if(p != buf) { assert(p - buf > 3); p -= 3; /* for the ||| */ *p = '\0'; } return TM_OK; } int tm_topicmap_model_loaded(TMTopicMap self, const char* name) { TMList mp; for(mp=self->models;mp;mp=mp->next) { TMModel m = (TMModel)mp->content; if( strcmp(m->name,name) == 0) return 1; } return 0; } #endif extern TMError parse(TMTopicMap topicmap, const char *query, TMQLNode *ptree); TMError tm_topicmap_query(TMTopicMap self, const char *query, TMResult *result) { TMError e; TMQLNode tree; TM_ENTER; e = parse(self,query,&tree); if(e != TM_OK) { TM_RETURN(e); } e = tm_qlnode_eval(tree,self,result); tm_qlnode_delete(&tree); if(e != TM_OK) { TM_RETURN(e); } TM_RETURN(TM_OK); } /* ====================================================================== */ TMError tm_qlnode_eval_property_condition(TMQLNode self,TMTopicMap topicmap,TMTopicSet *result); TMError tm_qlnode_eval_value(TMQLNode self,TMTopicMap topicmap,TMValueType *pvt,void **value); TMError tm_qlnode_eval_subject(TMQLNode self,TMTopicMap topicmap,void **valp) { TMQLNode pvpair_list; TMSubject sbj; TM_ENTER; assert(self->args[0]->type == TM_QLNODE_PVPAIRLIST); TM_NEW(self->pool,sbj); TM_INIT_SUBJECT(sbj); pvpair_list = self->args[0]; do { TMError e; TMProperty prop; void *val; TMValueType vt_check; TMQLNode pvpair = pvpair_list->args[0]; prop = tm_topicmap_get_property_by_name(topicmap,(char*)pvpair->args[0]); assert(prop); TMTRACE(TM_PARSE_TRACE,"in pvpairlist loop for %s\n" _ prop->fullname); e = tm_qlnode_eval_value(pvpair->args[1],topicmap,&vt_check,&val); assert( vt_check == prop->value_type); TM_SUBJECT_ADD(sbj,prop,val,0); TMTRACE(TM_PARSE_TRACE,"added to subject\n"); } while( (pvpair_list = pvpair_list->args[1]) != NULL); *valp = sbj; TM_RETURN(TM_OK); } TMError tm_qlnode_eval_value(TMQLNode self,TMTopicMap topicmap,TMValueType *pvt,void **value) { void *v; TM_ENTER; TMTRACE(TM_PARSE_TRACE,"enter\n"); assert(self); assert(self->type == TM_QLNODE_VALUE); if(self->args[1] == NULL) { *value = NULL; *pvt = NULL; return TM_OK; } TMTRACE(TM_PARSE_TRACE,"XX %s\n" _ ((TMValueType)(self->args[0]))->name); v = tm_value_new_from_string(self->pool, ((TMValueType)(self->args[0])), (const char*)self->args[1]); assert(value); *pvt = (TMValueType)(self->args[0]); *value = v; TMTRACE(TM_PARSE_TRACE,"exit\n"); TM_RETURN(TM_OK); } TMError tm_qlnode_eval_predicate(TMQLNode self,TMTopicMap topicmap,TMTopicSet *result) { const char *uri,*opstring; TMProperty prop; int opcode; TMTopicSet tset; void *value; TMValueType vt; TMValueStoreScan vscan; TMValueStore vstore; TMPropertyStore pstore; TMError e; int is_sbj = 0; TM_ENTER; assert(self); assert(self->type == TM_QLNODE_PREDICATE); tset = tm_topicset_new(self->pool,100); *result = tset; uri = (const char*)self->args[0]; opstring = (const char*)self->args[1]; prop = tm_topicmap_get_property_by_name(topicmap,uri); /* set has been created. If prop not in map, return */ if(!prop) { assert( ! ((strcmp(opstring,"EQU") == 0) && (value == NULL)) ); TM_RETURN(TM_OK); } _get_stores(topicmap,prop,&pstore,&vstore); if(self->args[2]->type == TM_QLNODE_SUBJECT) { TMTopic t; TMTRACE(TM_PARSE_TRACE,"we have a URI op subject predicate\n"); e = tm_qlnode_eval_subject(self->args[2],topicmap,&value); assert(e == TM_OK); e = tm_topicmap_lookup_topic_by_subject(topicmap,(TMSubject)value,&t); assert(e == TM_OK); ((TMSubject)value)->topic = t; is_sbj = 1; TMTRACE(TM_PARSE_TRACE,"end of processing URI op subject predicate's subject\n"); } else { e = tm_qlnode_eval_value(self->args[2],topicmap,&vt,&value); assert(e == TM_OK); } if( (strcmp(opstring,"EQU") == 0) && (value != NULL) ) { int i,len; TMVid vid; TMTopic *topics; if( (e = tm_value_store_lookup_vid(vstore,value,0,TM_VALUE_LOOKUP,&vid)) != TM_OK) TM_RETURN(e); if(!vid) TM_RETURN(TM_OK); if( (e = tm_property_store_lookup_topics(pstore,vid,&topics,&len)) != TM_OK) TM_RETURN(e); for(i=0;imeta_store,&max)) != TM_OK) TM_RETURN(e); for(t=1;t<=max;t++) { TMVid vid; if( tm_meta_store_is_disposed(topicmap->meta_store,t) ) continue; if( (e = tm_property_store_get_vid_of_topic(pstore,t,&vid)) != TM_OK) TM_RETURN(e); if(vid) continue; tm_topicset_add(tset,t); } } else if( (strcmp(opstring,"NEQ") == 0) && (value == NULL) ) { TMTopic t,max; if( (e = tm_meta_store_get_topicmax(topicmap->meta_store,&max)) != TM_OK) TM_RETURN(e); for(t=1;t<=max;t++) { TMVid vid; if( tm_meta_store_is_disposed(topicmap->meta_store,t) ) continue; if( (e = tm_property_store_get_vid_of_topic(pstore,t,&vid)) != TM_OK) TM_RETURN(e); if(!vid) continue; tm_topicset_add(tset,t); } } else { /* ATTENTION!! we need to lookup operator in properties value type. * Argument might be different type!! * FIXME: do type checking in OP somewhere!! */ opcode = tm_valuetype_parse_opstring(prop->value_type,opstring); if(opcode == 0) assert(0); TMTRACE(TM_PARSE_TRACE,"now opening vscan\n"); if( (e = tm_value_store_scan_open(vstore,tm_topicmap_get_current_transaction_pool(topicmap), opcode, value , &vscan )) != TM_OK) TM_RETURN(e); TMTRACE(TM_PARSE_TRACE,"opened\n"); while(! tm_value_store_scan_finished(vstore,vscan) ) { TMVid vid; int i,len; TMTopic *topics; if( (e = tm_value_store_scan_fetch(vstore,vscan,&vid)) != TM_OK) TM_RETURN(e); /* fprintf(stderr,"\nVID:====== %d\n\n", vid); */ if( (e = tm_property_store_lookup_topics(pstore,vid,&topics,&len)) != TM_OK) TM_RETURN(e); for(i=0;ipool,(TMSubject)value); TM_FREE(self->pool,value); /* fprintf(stderr,"ZZ02-5\n"); */ } else { /* fprintf(stderr,"ZZ03\n"); */ tm_value_delete(self->pool,vt,&value); /* fprintf(stderr,"ZZ04\n"); */ } } TM_RETURN(TM_OK); } TMError tm_qlnode_eval_select(TMQLNode self,TMTopicMap topicmap,void **result) { TMResult r; TMTopicSet tset; TMQLNode node; TMList prop_uris = NULL; TMError e; TM_ENTER; TMTRACE(TM_PARSE_TRACE,"enter\n"); assert(self); assert(self->type == TM_QLNODE_SELECT); if( (e = tm_qlnode_eval_property_condition(self->args[1],topicmap,&tset)) != TM_OK) TM_RETURN(e); TM_NEW(self->pool,r); r->pool = self->pool; r->tm = tm_topicmap_get_tm(topicmap); assert(tset); if(!self->args[0]) /* no prop_commalist */ { int i,len; r->topicmap = tm_topicmap_new(tm_get_pool(r->tm),r->tm); r->type = TM_RESULT_TOPICMAP; if( tm_topicmap_set_storage(r->topicmap,"MemStore") != TM_OK) { assert(0); /* tk_err_exit("unable to set storage, %s", tm_get_error(tm) ); */ } if( tm_topicmap_open(r->topicmap,"Result") != TM_OK) { assert(0); /* tk_err_exit("unable to open topicmap %s, %s\n", topicmap_name, tm_get_error(tm) ); */ } if( tm_topicmap_start_transaction(r->topicmap,"AddResult") != TM_OK) { assert(0); /* tk_err_exit("unable to open topicmap %s, %s\n", topicmap_name, tm_get_error(tm) ); */ } len = tm_topicset_size(tset); for(i=0;itopicmap)) != TM_OK) TM_RETURN(e); } if( (e=tm_topicmap_fully_merge(r->topicmap)) != TM_OK) TM_RETURN(e); if( tm_topicmap_end_transaction(r->topicmap) != TM_OK) { assert(0); /* tk_err_exit("unable to open topicmap %s, %s\n", topicmap_name, tm_get_error(tm) ); */ } *result = r; tm_topicset_delete(&tset); TM_RETURN(TM_OK); } if(self->args[0]->args[0] == NULL) /* SELECT * query */ { int i,len; r->type = TM_RESULT_SUBJECTS; r->nsubjects = tm_topicset_size(tset); r->subjects = NULL; r->topics = NULL; if(r->nsubjects > 0) { r->subjects = (struct TMSubject*)TM_ALLOC(self->pool,r->nsubjects * sizeof(struct TMSubject)); r->topics = (TMTopic*)TM_ALLOC(self->pool,r->nsubjects * sizeof(TMTopic)); len = tm_topicset_size(tset); for(i=0;itopics[i] = 0; TM_INIT_SUBJECT(&(r->subjects[i])); r->subjects[i].topic = t; if( (e=_make_subject(topicmap,&(r->subjects[i]) )) != TM_OK) TM_RETURN(e); for(j=0;jsubjects[i].N;j++) { assert( r->subjects[i].props[j].prop); } /* fprintf(stderr,"0000 -> %d\n" , t); */ r->topics[i] = t; } } /* if size > 0 */ *result = r; tm_topicset_delete(&tset); TM_RETURN(TM_OK); } r->type = TM_RESULT_TABLE; node = self->args[0]; do { const char *uri = (const char *)node->args[0]; prop_uris = tm_list_push(self->pool,prop_uris,(char*)uri); } while( (node = node->args[1]) != NULL); { int i; int j; TMList lp; r->nrows = tm_topicset_size(tset); r->ncols = tm_list_size(prop_uris); r->prop_heading = (TMProperty*)TM_ALLOC(self->pool, r->ncols * sizeof(TMProperty)); for(j=0,lp=prop_uris;jncols;j++,lp=lp->next) { TMProperty p; p = tm_topicmap_get_property_by_name(topicmap,(char*)lp->content); assert(p); r->prop_heading[j] = p; } assert(r->nrows > 0); r->vtable = TM_ALLOC(self->pool, r->nrows * sizeof(void*)); for(i=0;inrows;i++) { TMTopic t; void **row; assert(r->ncols > 0); row = TM_ALLOC(self->pool, r->ncols * sizeof(void*)); t = tm_topicset_get(tset,i); for(j=0;jncols;j++) { void *value; TMProperty p = r->prop_heading[j]; if( (e = tm_topicmap_get_property(topicmap,t,p,&value)) != TM_OK) { assert(0); /* FIXME */ exit(1); } row[j] = value; } r->vtable[i] = row; } *result = r; } tm_topicset_delete(&tset); TMTRACE(TM_PARSE_TRACE,"exit (with propcommalist)\n"); TM_RETURN(TM_OK); } TMError tm_qlnode_eval_property_condition(TMQLNode self,TMTopicMap topicmap,TMTopicSet *result) { TMError e; TM_ENTER; switch(self->type) { case TM_QLNODE_PREDICATE: TM_RETURN(tm_qlnode_eval_predicate(self,topicmap,result)); case TM_QLNODE_OR: { TMTopicSet leftset,rightset; int i,len; if( (e=tm_qlnode_eval_property_condition(self->args[0],topicmap,&leftset)) != TM_OK) TM_RETURN(e); if( (e=tm_qlnode_eval_property_condition(self->args[1],topicmap,&rightset)) != TM_OK) TM_RETURN(e); len = tm_topicset_size(leftset); for(i =0; ipool,100); if( (e=tm_qlnode_eval_property_condition(self->args[0],topicmap,&leftset)) != TM_OK) TM_RETURN(e); if( (e=tm_qlnode_eval_property_condition(self->args[1],topicmap,&rightset)) != TM_OK) TM_RETURN(e); len = tm_topicset_size(leftset); for(i =0; itransactions) > 0); tx = (TMTransaction)tm_stack_top(self->transactions); TM_RETURN(tx); } TMModel tm_topicmap_get_model_by_name(TMTopicMap self,const char *name) { TMList lp; assert(self); assert(name); TMTRACE(TM_GRAPH_TRACE, "enter, name=%s\n" _ name); for(lp = self->models; lp; lp = lp->next ) { TMTRACE(TM_GRAPH_TRACE, "Model: %s\n" _ ((TMModel)lp->content)->name); if(strcmp( ((TMModel)lp->content)->name,name) == 0) { TMTRACE(TM_GRAPH_TRACE, "exit (found)\n"); TM_RETURN((TMModel)lp->content); } } TMTRACE(TM_GRAPH_TRACE, "exit (not found)\n"); TM_RETURN(NULL); } TMError _load_model(TMTopicMap self,TMModel model) { /* TMError e; TMList ap; */ TMList pp; assert(self); assert(model); TMTRACE(TM_GRAPH_TRACE,"enter [model=%s]\n" _ model->name); for(pp = model->properties; pp; pp = pp->next) { TMProperty prop = (TMProperty)pp->content; TMTRACE(TM_GRAPH_TRACE,"putting to proptable %s\n" _ prop->fullname); tm_table_put(self->prop_table,prop->fullname,prop); } /* FIXME: in order to allow TMA defs to use props of the TMA itself, we need to * mark TMA as loaded now. FIXME: there is more to this - or? */ self->models = tm_list_append(self->pool,self->models,model); #if 0 for(ap = model->atypes; ap; ap=ap->next) { TMList rp; TMAssertionType at = (TMAssertionType)ap->content; TMTRACE(TM_GRAPH_TRACE,"Loading assertion type %s\n" _ at->name); if( (e = tm_topicmap_add_subject(self, at->subject, NULL)) != TM_OK) return e; for(rp = at->roles; rp; rp=rp->next) { TMRoleType r = (TMRoleType)rp->content; TMTRACE(TM_GRAPH_TRACE,"loading role type %s\n" _ r->name); if( (e = tm_topicmap_add_subject(self, r->subject, NULL)) != TM_OK) return e; } } for(ap = model->subjects; ap; ap=ap->next) { if( (e = tm_topicmap_add_subject(self, (TMSubject)ap->content, NULL)) != TM_OK) return e; } tm_topicmap_fully_merge(self); #endif TM_LOG(self->tm,TM_LOG_INFO,"[tm] added schema '%s'" _ model->name); TMTRACE(TM_GRAPH_TRACE,"exit [model=%s]\n" _ model->name); return TM_OK; } int _have_stores(TMTopicMap self, TMProperty prop, TMPropertyStore *pstore, TMValueStore *vstore) { TMValueStore v; TMPropertyStore p; p = (TMPropertyStore)tm_table_get(self->propname_to_pstore_table,prop->fullname); if(p == NULL) { return 0; } assert(p); v = (TMValueStore)tm_table_get(self->propname_to_vstore_table,prop->fullname); assert(v); *pstore = p; *vstore = v; return 1; } TMError _get_stores(TMTopicMap self, TMProperty prop, TMPropertyStore *pstore, TMValueStore *vstore) { TMError e; TMValueStore v; TMPropertyStore p; p = (TMPropertyStore)tm_table_get(self->propname_to_pstore_table,prop->fullname); if(p == NULL) { if( (e = _open_stores(self,prop)) != TM_OK) return e; p = (TMPropertyStore)tm_table_get(self->propname_to_pstore_table,prop->fullname); } assert(p); v = (TMValueStore)tm_table_get(self->propname_to_vstore_table,prop->fullname); assert(v); *pstore = p; *vstore = v; return TM_OK; } TMError _open_stores(TMTopicMap self, TMProperty prop) { TMError e; TMValueStore vstore; TMPropertyStore pstore; TMTRACE(TM_GRAPH_TRACE, "loading property %s (%s)\n" _ prop->name _ prop->value_type->name ); vstore = tm_value_store_new(self->storage_descriptor,self->storage_handle,prop); if(! vstore) { TMTRACE(TM_GRAPH_TRACE,"no value store found for value type %s\n" _ prop->value_type->name); tm_set_error(self->tm,"no value store found for value type %s\n", prop->value_type->name); assert(0); return TM_E_VALUE_STORE_NOT_FOUND; /* FIXME! */ } if( (e = tm_value_store_open(vstore)) != TM_OK) { /* FIXME cleanup of all the above */ assert(0); return e; } pstore = tm_property_store_new(self->storage_descriptor, self->storage_handle, prop, vstore ); if( (e = tm_property_store_open(pstore)) != TM_OK) { /* FIXME: cleanup */ assert(0); return e; } self->property_stores = tm_list_push(self->pool,self->property_stores,pstore); self->value_stores = tm_list_push(self->pool,self->value_stores,vstore); tm_table_put(self->propname_to_pstore_table,prop->fullname,pstore); tm_table_put(self->propname_to_vstore_table,prop->fullname,vstore); return TM_OK; } TMError _pstore_get(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, TMTopic topic, void **valp) { TMVid vid; TMError e; TM_ENTER; *valp = NULL; if( (e = tm_property_store_get_vid_of_topic(pstore,topic,&vid)) != TM_OK) return e; if(!vid) return TM_OK; if( (e = tm_value_store_get_value(vstore,vid,tm_topicmap_get_current_transaction_pool(self),valp)) != TM_OK) return e; TM_RETURN(TM_OK); } /* ok */ TMError _topicmap_create_topic(TMTopicMap self, TMTopic *np) { TMError e; TMTransaction t; assert(self); assert(np); TM_ENTER; t = current_transaction(self); if( (e = tm_meta_store_get_new_topic(self->meta_store,np, tm_transaction_get_tag(t) )) != TM_OK) return e; TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s][t%d] created" _ tm_transaction_get_tag(t) _ *np); TM_RETURN(TM_OK); } TMError tm_topicmap_add_property_to_topic(TMTopicMap self, TMTopic topic, TMProperty prop, const void *value,int vflags) { TMError e; TMPropertyStore pstore; TMValueStore vstore; TMVid vid; assert(self); assert(topic); assert(value); /* FIXME: if number, it may be 0 !!! */ TMTRACE(TM_GRAPH_TRACE, "enter prop=%s topic=%d\n" _ prop->fullname _ topic); /* autoload */ if( tm_topicmap_get_property_by_name(self,prop->fullname) == NULL) { if( (e = tm_topicmap_require_model(self,prop->model)) != TM_OK) TM_RETURN(e); } if( (e = _get_stores(self,prop,&pstore,&vstore)) != TM_OK) TM_RETURN(e); /* here we do the magic replacement of any TMTopicValue components * with topics. FIXME: need fine name for this function. */ if( tm_valuetype_values_contain_topics(prop->value_type) ) { if( (e = XXXXX_do(self,prop,(void*)value)) != TM_OK) TM_RETURN(e); } TMTRACE(TM_GRAPH_TRACE, "value is:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,value); if( (e = tm_value_store_lookup_vid(vstore,value,vflags, TM_VALUE_LOOKUP_OR_CREATE,&vid)) != TM_OK) { assert(0); /* just that we catch it during development! (FIXME) */ TM_RETURN(e); } assert(vid); if( (e = tm_property_store_insert(pstore,topic,vid)) != TM_OK) TM_RETURN(e); TM_LOG(self->tm,TM_LOG_INFO,"[tm|%s][t%d] added %s=%s" _ tm_transaction_get_tag(current_transaction(self)) _ topic _ prop->fullname _ tm_value_as_string(prop->value_type,value,NULL,0) ); TM_RETURN(TM_OK); } TMError tm_topicmap_fully_merge(TMTopicMap self) { TMList mp,lp,kp; /* int count = 0; */ TMError e; TMTransaction tx; TMPool pool; TM_ENTER; tx = current_transaction(self); TM_LOG(self->tm,TM_LOG_DEBUG,"[tm|%s] starting merge of added map" _ tm_transaction_get_tag(tx) ); assert(self->is_open); assert(self->merge_lists == NULL); pool = tm_topicmap_get_current_transaction_pool(self); while(1) { for(mp = self->models; mp; mp=mp->next) { TMModel model = (TMModel)mp->content; TM_LOG(self->tm,TM_LOG_DEBUG,"[tm|%s] Model: %s" _ tm_transaction_get_tag(tx) _ model->name); for(lp = model->properties; lp; lp=lp->next) { TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)lp->content; TM_LOG(self->tm,TM_LOG_DEBUG,"[tm|%s] Property: %s" _ tm_transaction_get_tag(tx) _ prop->fullname); if(prop->type != TM_SIDP) continue; if(!_have_stores(self,prop,&pstore,&vstore)) continue; if( prop->equality_code && !vstore_is_normalized(self,prop->fullname) ) { TM_LOG(self->tm,TM_LOG_DEBUG, "[tm|%s] Normalizing vstore for %s" _ tm_transaction_get_tag(tx) _ prop->fullname); e = _normalize_vstore(self,prop,pstore,vstore); assert(e == TM_OK); set_vstore_normalized_state(self,prop->fullname,1); } TM_LOG(self->tm,TM_LOG_DEBUG, "[tm|%s] Normalizing pstore for %s" _ tm_transaction_get_tag(tx) _ prop->fullname); e = tm_property_store_normalize(pstore,self,NULL,NULL); assert(e == TM_OK); /*FIXME */ } } if(self->merge_lists == NULL) break; for(lp = self->merge_lists; lp; lp=lp->next) { TMTopicSet other; TMTopic new_topic; other = (TMTopicSet)lp->content; if( (e = _topicmap_create_topic(self,&new_topic)) != TM_OK) TM_RETURN(e); self->new_topic_list = tm_list_append(pool,self->new_topic_list, (void*)new_topic); /* fprintf(stderr,"MERGELIST: [%6d]",new_topic); tm_topicset_print(other,stderr); fprintf(stderr,"\n"); */ } #if 0 for(lp = self->merge_lists,kp=self->new_topic_list; lp && kp; lp=lp->next,kp=kp->next) { TMTopicSet other; TMTopic new_topic = (TMTopic)kp->content; other = (TMTopicSet)lp->content; fprintf(stderr,"MERGELIST: [%6d]",new_topic); tm_topicset_print(other,stderr); fprintf(stderr,"\n"); } #endif /* substitute all topics in property stores */ for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; TMTRACE(TM_GRAPH_TRACE,"replace topics loop for model %s\n" _ m->name); for(pp=m->properties; pp; pp=pp->next) { TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; for(lp = self->merge_lists,kp=self->new_topic_list; lp && kp; lp=lp->next,kp=kp->next) { if( (e = _pstore_replace_topics(self, prop,pstore,vstore, (TMTopic)kp->content, (TMTopicSet)lp->content)) != TM_OK) TM_RETURN(e); } } } /* substitute all topics in property stores */ for(mp=self->models;mp;mp=mp->next) { TMList pp; TMError e; TMModel m = (TMModel)mp->content; TMTRACE(TM_GRAPH_TRACE,"replace topics in values loop for model %s\n" _ m->name); for(pp=m->properties; pp; pp=pp->next) { TMPropertyStore pstore; TMValueStore vstore; TMProperty prop = (TMProperty)pp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; for(lp = self->merge_lists,kp=self->new_topic_list; lp && kp; lp=lp->next,kp=kp->next) { if( (e = _pstore_replace_topics_in_values(self, prop,pstore,vstore, (TMTopic)kp->content, (TMTopicSet)lp->content)) != TM_OK) TM_RETURN(e); } } } TM_LOG(self->tm,TM_LOG_DEBUG,"[tm|%s] values stores now normalized, going for pstores now" _ tm_transaction_get_tag(tx) ); for(lp = self->merge_lists;lp; lp=lp->next) { int len,i; TMTopicSet s = (TMTopicSet)lp->content; len = tm_topicset_size(s); for(i=0;imeta_store, tm_topicset_get(s,i)); } tm_topicset_delete( &s ); } tm_list_delete(pool,&self->merge_lists); tm_list_delete(pool,&self->new_topic_list); self->merge_lists = NULL; self->new_topic_list = NULL; } /* while (1) */ TM_RETURN(TM_OK); } TMError tm_topicmap_get_valuetype(TMTopicMap self, const char *modelname,const char *propname, TMValueType *vtype) { TMModel model; TMProperty prop; assert(self); assert(modelname); assert(propname); *vtype = NULL; if( (model = tm_topicmap_get_model_by_name(self,modelname)) == NULL) { tm_set_error(self->tm, "model not loaded %s %s", modelname,propname); return TM_EMODEL_NOT_LOADED; } if( (prop = tm_model_get_property(model,propname)) == NULL) { tm_set_error(self->tm, "property %s not found in model %s", propname,modelname); return TM_E_PROP_NOT_FOUND; } *vtype = prop->value_type; return TM_OK; } TMError _internal_add_topic(TMTopicMap self, TMSubject subject, TMTopic *pt) { TMError e; int i; TMTopic topic; TM_ENTER; assert(self); /* FIXME: iterate props and check if models/props are loaded! */ /* check subject for duplicate props and remove check in add_prop... FIXME */ /* we allways create a new topic */ if( (e = _topicmap_create_topic(self,&topic)) != TM_OK) TM_RETURN(e); *pt = topic; /* Allow anonymous topic! Propably we do not want to allow this!! (FIXME) */ if(subject == NULL) { assert(0); /* let's at least detect this now */ TM_RETURN(TM_OK); } /* assert(subject->topic == 0); */ assert(subject->N > 0); /* FIXME: handle somehow! */ /* now add each property to the topic */ for(i=0;iN;i++) { if( (e = tm_topicmap_add_property_to_topic(self,topic, subject->props[i].prop, subject->props[i].value, subject->props[i].vflags)) != TM_OK) { TM_RETURN(e); } } TM_RETURN(TM_OK); } TMError XXXXX_do(TMTopicMap self,TMProperty prop, void*value) { TMList vals,vp; vals = tm_value_get_tvals(prop->value_type, tm_topicmap_get_current_transaction_pool(self), value); /* for(vp=vals;vp;vp=vp->next) { TMTopicValue tval; TMSubject sbj; tval = (TMTopicValue)vp->content; assert(tval->topic == 0); assert(tval->symbol == NULL); sbj = tval->subject; } */ for(vp=vals;vp;vp=vp->next) { TMTopic topic; TMSubject sbj; sbj = (TMSubject)vp->content; /* fprintf(stderr,"___%d\n",sbj->topic); assert(sbj->topic == 0); */ if(sbj->symbol == NULL) { _internal_add_topic(self,sbj,&topic); } else { topic = tm_transaction_get_topic( current_transaction(self), sbj->symbol); assert(topic); /* FIXME */ } sbj->topic = topic; } tm_list_delete(tm_topicmap_get_current_transaction_pool(self), &vals); return TM_OK; } TMError YYYYY_do(TMTopicMap self,TMProperty prop, void*value) { TMList vals,vp; TM_ENTER; vals = tm_value_get_tvals(prop->value_type, tm_topicmap_get_current_transaction_pool(self), value); for(vp=vals;vp;vp=vp->next) { TMSubject sbj; TMError e; sbj = (TMSubject)vp->content; assert(sbj->topic != 0); sbj->N = 0; if( (e = _make_subject(self,sbj)) != TM_OK) TM_RETURN(e); } tm_list_delete(tm_topicmap_get_current_transaction_pool(self), &vals); TM_RETURN(TM_OK); } TMTopic tm_topicmap_add_mergelist(TMTopicMap self, TMTopic *array, int len,TMVid vid,TMProperty prop) { TMTopicSet set; TMList lp,prev = NULL; /* TMList tmp = NULL; TMTopic new_topic,t; */ TMPool pool = tm_topicmap_get_current_transaction_pool(self); int i; /* fprintf(stdout,"MERGELIST: %-20s VID %6d -> ",prop->name,vid ); for(i=0;imerge_lists; lp; lp=lp->next) { TMTopicSet other; TMTRACE(TM_GRAPH_TRACE,"----- LOOP -----\n"); other = (TMTopicSet)lp->content; TMTRACE(TM_GRAPH_TRACE,"checking if current disjoint with new one\n"); /* tm_topicset_print(set,stderr); tm_topicset_print(other,stderr); fprintf(stderr,"\n\n"); */ if( ! tm_topicset_disjoint( other , set )) { TMTRACE(TM_GRAPH_TRACE,"not disjoint -> 'unite'\n"); for(i=0;imerge_lists); /* special case: first element in list */ TMTRACE(TM_GRAPH_TRACE,"prev is NULL\n"); self->merge_lists = lp->next; TMTRACE(TM_GRAPH_TRACE,"reasigned self->merge_lists\n"); lp->next = NULL; /* or list_delete will erase whole list!!! */ tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&lp); TMTRACE(TM_GRAPH_TRACE,"deleted lp\n"); lp = self->merge_lists; TMTRACE(TM_GRAPH_TRACE,"lp now points to merge_lists\n"); } else { assert(prev->next == lp); TMTRACE(TM_GRAPH_TRACE,"XX mark3\n"); prev->next=lp->next; TMTRACE(TM_GRAPH_TRACE,"XX mark7\n"); lp->next = NULL; tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&lp); TMTRACE(TM_GRAPH_TRACE,"XX mark9\n"); lp = prev; } /* FIXME: do we need to delete topic set when taking out? */ TMTRACE(TM_GRAPH_TRACE,"XX mark4 (end of if)\n"); } TMTRACE(TM_GRAPH_TRACE,"XX mark1\n"); prev = lp; if(!lp) { TMTRACE(TM_GRAPH_TRACE,"XX mark2\n"); break; } TMTRACE(TM_GRAPH_TRACE,"set prev to lp (bottom of loop)\n"); } TMTRACE(TM_GRAPH_TRACE,"loop exited\n"); TMTRACE(TM_GRAPH_TRACE,"pushing set onto merge lists\n"); self->merge_lists = tm_list_push(tm_topicmap_get_current_transaction_pool(self),self->merge_lists,set); return(0); } TMError _normalize_vstore(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore) { TMValueStoreScan outer_vscan; TMError e; int opcode; TMList lp,vidset_list = NULL; TMPool pool = tm_topicmap_get_current_transaction_pool(self); assert(prop->equality_code); /* we only get called if this is true */ /* get the operator that allows us to detect equivalent values */ opcode = tm_valuetype_parse_opstring(prop->value_type, prop->equality_code); assert(opcode); /* FIXME: error hdl */ if( (e = tm_value_store_scan_open(vstore, tm_topicmap_get_current_transaction_pool(self), TM_OP_FULLSCAN, NULL, &outer_vscan )) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE,"outer vscan opened\n"); while(! tm_value_store_scan_finished(vstore,outer_vscan) ) { TMVid outer_vid; void *outer_val; TMList this_equ_list = NULL; TMValueStoreScan inner_vscan; if( (e = tm_value_store_scan_fetch(vstore,outer_vscan, &outer_vid)) != TM_OK) return (e); if( (e = tm_value_store_get_value(vstore,outer_vid, pool, &outer_val)) != TM_OK) return (e); TMTRACE(TM_GRAPH_TRACE,"got outer value (vid=%d):\n" _ outer_vid ); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,outer_val); if( (e = tm_value_store_scan_open(vstore,tm_topicmap_get_current_transaction_pool(self), opcode, outer_val, &inner_vscan )) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE,"inner vscan opened\n"); while(! tm_value_store_scan_finished(vstore,inner_vscan) ) { TMVid inner_vid; if( (e = tm_value_store_scan_fetch(vstore,inner_vscan, &inner_vid)) != TM_OK) return (e); TMTRACE(TM_GRAPH_TRACE,"got inner vid: %d\n" _ inner_vid); if(inner_vid <= outer_vid) continue; TMTRACE(TM_GRAPH_TRACE,"inner_vid > outer_vid; pushing to equ list\n"); this_equ_list = tm_list_push( pool, this_equ_list, (void*)inner_vid); } /* while inner_vscan has more */ if( (e = tm_value_store_scan_close(vstore,inner_vscan)) != TM_OK) return e; tm_value_delete(pool,prop->value_type,&outer_val); if(!this_equ_list) /* if we had no equivalents at all */ continue; /* ...no need to do something */ /* add outer to this list */ this_equ_list = tm_list_push( pool, this_equ_list, (void*)outer_vid); vidset_list = add_to_vidset_list(pool,vidset_list, this_equ_list); tm_list_delete(pool,&this_equ_list); } /* while outer_vscan has more */ /* FIXME: there might be some improvements if we pass vid to scan_open instead of value*/ if( (e = tm_value_store_scan_close(vstore,outer_vscan)) != TM_OK) return e; /* fprintf(stderr,"*******************************************\n"); for(lp=vidset_list;lp;lp=lp->next) tm_topicset_print(lp->content,stderr),fprintf(stderr,"\n"); fprintf(stderr,"*******************************************\n"); */ for(lp=vidset_list;lp;lp=lp->next) { int size,i; TMVid new_vid; void *new_value = NULL; TMTopicSet set = (TMTopicSet)lp->content; size = tm_topicset_size(set); /* tm_topicset_print(set,stderr),fprintf(stderr,"\n"); */ for(i=0;ivalue_type,val); temp = tm_value_call(prop->value_type,new_value,prop->combination_code,pool,val); /* FIXME: delete vals */ new_value = temp; } TMTRACE(TM_GRAPH_TRACE, "new value is (in next line):\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,new_value); if( (e = tm_value_store_lookup_vid(vstore,new_value,0, TM_VALUE_LOOKUP_OR_CREATE, &new_vid)) != TM_OK) return(0); TMTRACE(TM_GRAPH_TRACE, "new vid is %d\n" _ new_vid); for(i=0;inext) { fprintf(stderr,"%6d ", (TMVid)lp->content); } fprintf(stderr,"\n"); */ for(lp=setlist;lp;lp=lp->next) { TMTopicSet set = (TMTopicSet)lp->content; if( ! tm_topicset_disjoint_list(set,vid_equ_list)) joinlist = tm_list_push(pool,joinlist, set); else nonjoinlist = tm_list_push(pool,nonjoinlist, set); } tm_list_delete(pool,&setlist); for(lp=vid_equ_list;lp;lp=lp->next) tm_topicset_add(joinset, (TMTopic)lp->content); for(lp=joinlist;lp;lp=lp->next) { TMTopicSet set = (TMTopicSet)lp->content; tm_topicset_join(joinset,set); tm_topicset_delete(&set); } tm_list_delete(pool,&joinlist); nonjoinlist = tm_list_push(pool,nonjoinlist, joinset); return nonjoinlist; } #if 0 int tm_topicmap_all_stores_normalized(TMTopicMap self) { TMList lp; for(lp=self->property_stores;lp;lp=lp->next) { TMPropertyStore pstore = (TMPropertyStore)lp->content; if( ! tm_property_store_is_normalized(pstore)) { return 0; } } return (1); } #endif #if 0 void _set_contradicting_values_error(TMTopicMap self,TMProperty prop, TMValueStore vstore,TMVid vid1,TMVid vid2) { void *v; char buf1[1024],buf2[1024]; /* FIXME: what about the ret codes of these functins.....?? */ tm_value_store_get_value(vstore,vid1,tm_topicmap_get_current_transaction_pool(self),&v); tm_value_to_string(prop->value_type,v,buf1,sizeof(buf1)); tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&v); tm_value_store_get_value(vstore,vid2,tm_topicmap_get_current_transaction_pool(self),&v); tm_value_to_string(prop->value_type,v,buf2,sizeof(buf2)); tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&v); tm_set_error(self->tm,"contradicting values for %s: %s contradicts %s", prop->fullname, buf1,buf2); } void _set_contradicting_values_error_2(TMTopicMap self,TMProperty prop, const void *v1,const void *v2) { char buf1[1024],buf2[1024]; /* FIXME: what about the ret codes of these functins.....?? */ tm_value_to_string(prop->value_type,v1,buf1,sizeof(buf1)); tm_value_to_string(prop->value_type,v2,buf2,sizeof(buf2)); tm_set_error(self->tm,"contradicting values for %s: %s contradicts %s", prop->fullname, buf1,buf2); } #endif /* * This function stores a value in the value store that 'belongs' to a * certain property store. The insertion process also deals with a * property defined equality definition if present. */ #if 0 TMError _pstore_vput(TMTopicMap self,TMProperty prop, TMPropertyStore pstore, TMValueStore vstore, const void* value, TMVid *pvid) { TMError e; TMList collected_topics = NULL, lp; TMList vids = NULL; int opcode; void *combined_value, *tmp; TMValueStoreScan vscan; TMTRACE(TM_GRAPH_TRACE, "enter\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,value); if( ! prop->equality_code ) { /* property does not contrain its range (it does not define * an equality function beyond value type equality). Thus * we can simply store the value. */ TMTRACE(TM_GRAPH_TRACE,"prop does not define equality code\n"); if( (e = tm_value_store_lookup_vid(vstore,value,0, TM_VALUE_LOOKUP_OR_CREATE,pvid)) != TM_OK) { assert(0); return e; } #ifndef NDEBUG { /* FIXME: debug code (adds one second to a 10 second parse of opera) */ TMVid i; if( (e = tm_value_store_lookup_vid(vstore,value,0, TM_VALUE_LOOKUP,&i)) != TM_OK) assert(i == *pvid); } #endif TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } TMTRACE(TM_GRAPH_TRACE, "property defines equality code\n"); TMTRACE(TM_GRAPH_TRACE, "getting 'all values that the prop considers " "to be equal to vputted value'\n"); /* get opcode from operator string in TMA definition */ opcode = tm_valuetype_parse_opstring(prop->value_type, prop->equality_code); if(!opcode) { tm_set_error(self->tm, "operator '%s' not defined for valuetype '%s'", prop->equality_code, prop->value_type->name); return TM_E_OP_UNDEFINED; } /* no argstring parsing needed, arg is value (Vq) */ if( (e = tm_value_store_scan_open(vstore,tm_topicmap_get_current_transaction_pool(self), opcode, value , &vscan )) != TM_OK) return e; while(! tm_value_store_scan_finished(vstore,vscan) ) { TMVid vid; TMList lp; int found = 0; tm_value_store_scan_fetch(vstore,vscan,&vid); /* FIXME: can we have doubles or is having doubles a programming error? */ /* FIXME: use if_contains function */ for(lp=vids;lp;lp=lp->next) { if( (TMVid)lp->content == vid) { found = 1; break; } } if(!found) { vids = tm_list_push(tm_topicmap_get_current_transaction_pool(self),vids,(void*)vid); } } if( (e = tm_value_store_scan_close(vstore,vscan)) != TM_OK) return e; combined_value = (void*)value; /* FIXME: const -> nonconst cast! */ TMTRACE(TM_GRAPH_TRACE, "start value (before combining things):\n" ); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,combined_value); TMTRACE(TM_GRAPH_TRACE, "iterating over vids and merging values\n" ); /* special code for handling common case that only on equal value is * found in scan and that thus we can handle this exactly like the * ordinary insert! (added 16 Nov 2003) */ if(vids && vids->next == NULL) { void *v; TMVid vid; TMTRACE(TM_GRAPH_TRACE,"special case (only one vid found in vscan)\n"); vid = (TMVid)vids->content; if( (e = tm_value_store_get_value(vstore,vid,tm_topicmap_get_current_transaction_pool(self),&v)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "got value\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,v); if(tm_value_equal(prop->value_type,value,v)) { /* value equal => handle like simple insert. */ tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&v); *pvid = vid; return TM_OK; } tm_value_delete(tm_topicmap_get_current_transaction_pool(self),prop->value_type,&v); /* values are not equal, so we need to do all the combination stuff * anyway now. Simply do now, what we would do in the nen-special case * anyway. */ } /* end special code */ for(lp=vids;lp;lp=lp->next) { int i,len; TMTopic *topics; TMList kp; TMList my_collected_topics = NULL; void *v; TMVid vid; TMTRACE(TM_GRAPH_TRACE,"loop vids\n"); vid = (TMVid)lp->content; TMTRACE(TM_GRAPH_TRACE, "in loop over vids to combine vid=%d\n" _ vid); if( (e = tm_value_store_get_value(vstore,vid,tm_topicmap_get_current_transaction_pool(self),&v)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "got value\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,v); if( (e = tm_property_store_lookup_topics(pstore,vid,&topics,&len)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "got topics\n"); for(i=0;inext) { if( (TMTopic)kp->content == topics[i]) { found = 1; break; } } if(!found) { collected_topics = tm_list_push(tm_topicmap_get_current_transaction_pool(self),collected_topics,(void*)topics[i]); } for(kp=my_collected_topics;kp;kp=kp->next) { if( (TMTopic)kp->content == topics[i]) { found = 1; break; } } if(!found) { my_collected_topics = tm_list_push(tm_topicmap_get_current_transaction_pool(self),my_collected_topics,(void*)topics[i]); } } TMTRACE(TM_GRAPH_TRACE, "now removing all the topics\n"); for(kp=my_collected_topics;kp;kp=kp->next) { TMTRACE(TM_GRAPH_TRACE, " .... %d\n" _ (TMTopic)kp->content ); if( (e = tm_property_store_remove(pstore,(TMTopic)kp->content) ) != TM_OK) return e; } TMTRACE(TM_GRAPH_TRACE, "removed all the topics\n"); tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&my_collected_topics); tmp = tm_value_call(prop->value_type,combined_value,prop->combination_code,v); /* ---- FIXME: does that break? tm_value_delete(prop->value_type,&combined_value); tm_value_delete(prop->value_type,&v); */ combined_value = tmp; TMTRACE(TM_GRAPH_TRACE, "combined value now:\n"); TMTRACE_VALUE(TM_GRAPH_TRACE,prop->value_type,combined_value); TMTRACE(TM_GRAPH_TRACE, "MARK 1\n"); } TMTRACE(TM_GRAPH_TRACE, "storing combined value\n" ); #ifndef NDEBUG { /* check that value is really not in store (so use of TM_VALUE_CREATE is ok) */ TMVid i; if( (e = tm_value_store_lookup_vid(vstore,combined_value,0, TM_VALUE_LOOKUP,&i)) != TM_OK) assert(i == 0); /* value MUST not be inm store */ } #endif /* here we use explicit create-only (FIXME: is that correct? - see tmm_pro) */ if( (e = tm_value_store_lookup_vid(vstore,combined_value,0,TM_VALUE_CREATE,pvid)) != TM_OK) return e; #ifndef NDEBUG { /* FIXME: debug code */ TMVid i; if( (e = tm_value_store_lookup_vid(vstore,combined_value,0, TM_VALUE_LOOKUP,&i)) != TM_OK) assert(i == *pvid); } #endif TMTRACE(TM_GRAPH_TRACE, "stored combined value as vid %d\n" _ *pvid); for(lp=collected_topics;lp;lp=lp->next) { if( (e = tm_property_store_insert(pstore,(TMTopic)lp->content,*pvid)) != TM_OK) return e; TMTRACE(TM_GRAPH_TRACE, "re-stored topic %d with this vid\n" _ (TMTopic)lp->content); } tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&collected_topics); tm_list_delete(tm_topicmap_get_current_transaction_pool(self),&vids); TMTRACE(TM_GRAPH_TRACE, "exit\n"); return TM_OK; } #endif void set_vstore_normalized_state(TMTopicMap self, const char *fullname, int b) { tm_table_put(self->vnorm_table,fullname,(void*)b); } int vstore_is_normalized(TMTopicMap self, const char *fullname) { TM_RETURN( (int)tm_table_get(self->vnorm_table,fullname) ); } TMError tm_topicmap_copy_topic(TMTopicMap self,TMTopic topic, TMTopicMap other) { TMError e; int i; struct TMSubject sbj; TM_ENTER; TM_INIT_SUBJECT(&sbj); sbj.topic = topic; if( (e = _make_subject(self,&sbj)) != TM_OK) TM_RETURN(e); sbj.topic = 0; /* insignificant outside map and required by XXXX_do, * which will be called inside add_topic()... */ if( (e = tm_topicmap_add_topic(other,&sbj,NULL)) != TM_OK) TM_RETURN(e); tm_subject_free_values(tm_topicmap_get_current_transaction_pool(self), &(sbj)); TM_RETURN(TM_OK); } TMError _make_subject(TMTopicMap self,TMSubject sbj) { TMError e; TMPool pool; TMList mp; TM_ENTER; pool = tm_topicmap_get_current_transaction_pool(self); assert(sbj->topic != 0); /* client's responsibility */ assert(sbj->N == 0); /* client's responsibility */ for(mp = self->models; mp; mp=mp->next) { TMModel model = (TMModel)mp->content; TMList lp; for(lp = model->properties; lp; lp=lp->next) { TMPropertyStore pstore; TMValueStore vstore; TMVid vid; void *val; TMProperty prop = (TMProperty)lp->content; if(!_have_stores(self,prop,&pstore,&vstore)) continue; if((e=tm_property_store_get_vid_of_topic(pstore,sbj->topic,&vid)) != TM_OK) TM_RETURN(e); if(!vid) continue; if( (e = tm_value_store_get_value(vstore,vid,pool,&val)) != TM_OK) TM_RETURN(e); /* here we do the magic replacement of any TMTopicValue components * with topics to some real world value. * FIXME: need fine name for this function. */ if( tm_valuetype_values_contain_topics(prop->value_type) ) { if( (e = YYYYY_do(self,prop,(void*)val)) != TM_OK) TM_RETURN(e); } TM_SUBJECT_ADD(sbj,prop,val,0); } } TM_RETURN(TM_OK); }