682 |
682 |
683 def execute(self, sessionid, rqlstring, args=None, build_descr=True, |
683 def execute(self, sessionid, rqlstring, args=None, build_descr=True, |
684 txid=None): |
684 txid=None): |
685 """execute a RQL query |
685 """execute a RQL query |
686 |
686 |
687 * rqlstring should be an unicode string or a plain ascii string |
687 * rqlstring should be a unicode string or a plain ascii string |
688 * args the optional parameters used in the query |
688 * args the optional parameters used in the query |
689 * build_descr is a flag indicating if the description should be |
689 * build_descr is a flag indicating if the description should be |
690 built on select queries |
690 built on select queries |
691 """ |
691 """ |
692 session = self._get_session(sessionid, setcnxset=True, txid=txid) |
692 session = self._get_session(sessionid, setcnxset=True, txid=txid) |
744 """raise `BadConnectionId` if the connection is no more valid, else |
744 """raise `BadConnectionId` if the connection is no more valid, else |
745 return its latest activity timestamp. |
745 return its latest activity timestamp. |
746 """ |
746 """ |
747 return self._get_session(sessionid, setcnxset=False).timestamp |
747 return self._get_session(sessionid, setcnxset=False).timestamp |
748 |
748 |
|
749 @deprecated('[3.19] use session or transaction data') |
749 def get_shared_data(self, sessionid, key, default=None, pop=False, txdata=False): |
750 def get_shared_data(self, sessionid, key, default=None, pop=False, txdata=False): |
750 """return value associated to key in the session's data dictionary or |
751 """return value associated to key in the session's data dictionary or |
751 session's transaction's data if `txdata` is true. |
752 session's transaction's data if `txdata` is true. |
752 |
753 |
753 If pop is True, value will be removed from the dictionary. |
754 If pop is True, value will be removed from the dictionary. |
756 `default` argument will be returned. |
757 `default` argument will be returned. |
757 """ |
758 """ |
758 session = self._get_session(sessionid, setcnxset=False) |
759 session = self._get_session(sessionid, setcnxset=False) |
759 return session.get_shared_data(key, default, pop, txdata) |
760 return session.get_shared_data(key, default, pop, txdata) |
760 |
761 |
|
762 @deprecated('[3.19] use session or transaction data') |
761 def set_shared_data(self, sessionid, key, value, txdata=False): |
763 def set_shared_data(self, sessionid, key, value, txdata=False): |
762 """set value associated to `key` in shared data |
764 """set value associated to `key` in shared data |
763 |
765 |
764 if `txdata` is true, the value will be added to the repository session's |
766 if `txdata` is true, the value will be added to the repository session's |
765 transaction's data which are cleared on commit/rollback of the current |
767 transaction's data which are cleared on commit/rollback of the current |
907 session.set_cnxset() |
909 session.set_cnxset() |
908 return session |
910 return session |
909 |
911 |
910 @contextmanager |
912 @contextmanager |
911 def internal_cnx(self): |
913 def internal_cnx(self): |
912 """return a Connection using internal user which have |
914 """Context manager returning a Connection using internal user which have |
913 every rights on the repository. The `safe` argument is dropped. all |
915 every access rights on the repository. |
914 hook are enabled by default. |
916 |
915 |
917 Beware that unlike the older :meth:`internal_session`, internal |
916 /!\ IN OPPOSITE OF THE OLDER INTERNAL_SESSION, |
918 connections have all hooks beside security enabled. |
917 /!\ INTERNAL CONNECTION HAVE ALL HOOKS ENABLED. |
|
918 |
|
919 This is to be used a context manager. |
|
920 """ |
919 """ |
921 with InternalSession(self) as session: |
920 with InternalSession(self) as session: |
922 with session.new_cnx() as cnx: |
921 with session.new_cnx() as cnx: |
923 # equivalent to cnx.security_enabled(False, False) because |
922 with cnx.security_enabled(read=False, write=False): |
924 # InternalSession gives full read access |
|
925 with cnx.allow_all_hooks_but('security'): |
|
926 with cnx.ensure_cnx_set: |
923 with cnx.ensure_cnx_set: |
927 yield cnx |
924 yield cnx |
928 |
|
929 |
925 |
930 def _get_session(self, sessionid, setcnxset=False, txid=None, |
926 def _get_session(self, sessionid, setcnxset=False, txid=None, |
931 checkshuttingdown=True): |
927 checkshuttingdown=True): |
932 """return the session associated with the given session identifier""" |
928 """return the session associated with the given session identifier""" |
933 if checkshuttingdown and self.shutting_down: |
929 if checkshuttingdown and self.shutting_down: |
943 |
939 |
944 # data sources handling ################################################### |
940 # data sources handling ################################################### |
945 # * correspondance between eid and (type, source) |
941 # * correspondance between eid and (type, source) |
946 # * correspondance between eid and local id (i.e. specific to a given source) |
942 # * correspondance between eid and local id (i.e. specific to a given source) |
947 |
943 |
948 def type_and_source_from_eid(self, eid, session): |
944 def type_and_source_from_eid(self, eid, cnx): |
949 """return a tuple `(type, extid, actual source uri)` for the entity of |
945 """return a tuple `(type, extid, actual source uri)` for the entity of |
950 the given `eid` |
946 the given `eid` |
951 """ |
947 """ |
952 try: |
948 try: |
953 eid = int(eid) |
949 eid = int(eid) |
954 except ValueError: |
950 except ValueError: |
955 raise UnknownEid(eid) |
951 raise UnknownEid(eid) |
956 try: |
952 try: |
957 return self._type_source_cache[eid] |
953 return self._type_source_cache[eid] |
958 except KeyError: |
954 except KeyError: |
959 etype, extid, auri = self.system_source.eid_type_source(session, |
955 etype, extid, auri = self.system_source.eid_type_source(cnx, eid) |
960 eid) |
|
961 self._type_source_cache[eid] = (etype, extid, auri) |
956 self._type_source_cache[eid] = (etype, extid, auri) |
962 return etype, extid, auri |
957 return etype, extid, auri |
963 |
958 |
964 def clear_caches(self, eids): |
959 def clear_caches(self, eids): |
965 etcache = self._type_source_cache |
960 etcache = self._type_source_cache |
973 except KeyError: |
968 except KeyError: |
974 etype = None |
969 etype = None |
975 rqlcache.pop( ('Any X WHERE X eid %s' % eid,), None) |
970 rqlcache.pop( ('Any X WHERE X eid %s' % eid,), None) |
976 self.system_source.clear_eid_cache(eid, etype) |
971 self.system_source.clear_eid_cache(eid, etype) |
977 |
972 |
978 def type_from_eid(self, eid, session): |
973 def type_from_eid(self, eid, cnx): |
979 """return the type of the entity with id <eid>""" |
974 """return the type of the entity with id <eid>""" |
980 return self.type_and_source_from_eid(eid, session)[0] |
975 return self.type_and_source_from_eid(eid, cnx)[0] |
981 |
976 |
982 def querier_cache_key(self, session, rql, args, eidkeys): |
977 def querier_cache_key(self, session, rql, args, eidkeys): |
983 cachekey = [rql] |
978 cachekey = [rql] |
984 for key in sorted(eidkeys): |
979 for key in sorted(eidkeys): |
985 try: |
980 try: |
1025 try: |
1020 try: |
1026 # bw compat: cnx may be a session, get at the Connection |
1021 # bw compat: cnx may be a session, get at the Connection |
1027 cnx = cnx._cnx |
1022 cnx = cnx._cnx |
1028 except AttributeError: |
1023 except AttributeError: |
1029 pass |
1024 pass |
1030 eid = self.system_source.extid2eid(cnx, extid) |
1025 with cnx.ensure_cnx_set: |
|
1026 eid = self.system_source.extid2eid(cnx, extid) |
1031 if eid is not None: |
1027 if eid is not None: |
1032 self._extid_cache[extid] = eid |
1028 self._extid_cache[extid] = eid |
1033 self._type_source_cache[eid] = (etype, extid, source.uri) |
1029 self._type_source_cache[eid] = (etype, extid, source.uri) |
1034 return eid |
1030 return eid |
1035 if not insert: |
1031 if not insert: |
1036 return |
1032 return |
1037 # no link between extid and eid, create one |
1033 # no link between extid and eid, create one |
1038 try: |
1034 with cnx.ensure_cnx_set: |
1039 eid = self.system_source.create_eid(cnx) |
1035 # write query, ensure connection's mode is 'write' so connections |
1040 self._extid_cache[extid] = eid |
1036 # won't be released until commit/rollback |
1041 self._type_source_cache[eid] = (etype, extid, source.uri) |
1037 cnx.mode = 'write' |
1042 entity = source.before_entity_insertion( |
1038 try: |
1043 cnx, extid, etype, eid, sourceparams) |
1039 eid = self.system_source.create_eid(cnx) |
1044 if source.should_call_hooks: |
1040 self._extid_cache[extid] = eid |
1045 # get back a copy of operation for later restore if necessary, |
1041 self._type_source_cache[eid] = (etype, extid, source.uri) |
1046 # see below |
1042 entity = source.before_entity_insertion( |
1047 pending_operations = cnx.pending_operations[:] |
1043 cnx, extid, etype, eid, sourceparams) |
1048 self.hm.call_hooks('before_add_entity', cnx, entity=entity) |
|
1049 self.add_info(cnx, entity, source, extid) |
|
1050 source.after_entity_insertion(cnx, extid, entity, sourceparams) |
|
1051 if source.should_call_hooks: |
|
1052 self.hm.call_hooks('after_add_entity', cnx, entity=entity) |
|
1053 return eid |
|
1054 except Exception: |
|
1055 # XXX do some cleanup manually so that the transaction has a |
|
1056 # chance to be commited, with simply this entity discarded |
|
1057 self._extid_cache.pop(extid, None) |
|
1058 self._type_source_cache.pop(eid, None) |
|
1059 if 'entity' in locals(): |
|
1060 hook.CleanupDeletedEidsCacheOp.get_instance(cnx).add_data(entity.eid) |
|
1061 self.system_source.delete_info_multi(cnx, [entity]) |
|
1062 if source.should_call_hooks: |
1044 if source.should_call_hooks: |
1063 cnx.pending_operations = pending_operations |
1045 # get back a copy of operation for later restore if |
1064 raise |
1046 # necessary, see below |
|
1047 pending_operations = cnx.pending_operations[:] |
|
1048 self.hm.call_hooks('before_add_entity', cnx, entity=entity) |
|
1049 self.add_info(cnx, entity, source, extid) |
|
1050 source.after_entity_insertion(cnx, extid, entity, sourceparams) |
|
1051 if source.should_call_hooks: |
|
1052 self.hm.call_hooks('after_add_entity', cnx, entity=entity) |
|
1053 return eid |
|
1054 except Exception: |
|
1055 # XXX do some cleanup manually so that the transaction has a |
|
1056 # chance to be commited, with simply this entity discarded |
|
1057 self._extid_cache.pop(extid, None) |
|
1058 self._type_source_cache.pop(eid, None) |
|
1059 if 'entity' in locals(): |
|
1060 hook.CleanupDeletedEidsCacheOp.get_instance(cnx).add_data(entity.eid) |
|
1061 self.system_source.delete_info_multi(cnx, [entity]) |
|
1062 if source.should_call_hooks: |
|
1063 cnx.pending_operations = pending_operations |
|
1064 raise |
1065 |
1065 |
1066 def add_info(self, session, entity, source, extid=None): |
1066 def add_info(self, session, entity, source, extid=None): |
1067 """add type and source info for an eid into the system table, |
1067 """add type and source info for an eid into the system table, |
1068 and index the entity with the full text index |
1068 and index the entity with the full text index |
1069 """ |
1069 """ |
1261 hm.call_hooks('after_delete_relation', cnx, |
1261 hm.call_hooks('after_delete_relation', cnx, |
1262 eidfrom=entity.eid, rtype=attr, eidto=prevvalue) |
1262 eidfrom=entity.eid, rtype=attr, eidto=prevvalue) |
1263 if relcache is not None: |
1263 if relcache is not None: |
1264 cnx.update_rel_cache_del(entity.eid, attr, prevvalue) |
1264 cnx.update_rel_cache_del(entity.eid, attr, prevvalue) |
1265 del_existing_rel_if_needed(cnx, entity.eid, attr, value) |
1265 del_existing_rel_if_needed(cnx, entity.eid, attr, value) |
1266 if relcache is not None: |
1266 cnx.update_rel_cache_add(entity.eid, attr, value) |
1267 cnx.update_rel_cache_add(entity.eid, attr, value) |
|
1268 else: |
|
1269 entity.cw_set_relation_cache(attr, 'subject', |
|
1270 cnx.eid_rset(value)) |
|
1271 hm.call_hooks('after_add_relation', cnx, |
1267 hm.call_hooks('after_add_relation', cnx, |
1272 eidfrom=entity.eid, rtype=attr, eidto=value) |
1268 eidfrom=entity.eid, rtype=attr, eidto=value) |
1273 finally: |
1269 finally: |
1274 if orig_edited is not None: |
1270 if orig_edited is not None: |
1275 entity.cw_edited = orig_edited |
1271 entity.cw_edited = orig_edited |