示例#1
0
文件: dbsdd.py 项目: whitten/vavista
    def fm_validate_insert(self, value):
        """
            This validator checks the field using the Fileman logic.
            Since it expects value to be in Fileman External format
            and we are using Internal Format, it is of limited use.

            Also, I don't know how it will work on a sub-file.
        """
        M.Globals["ERR"].kill()

        # Validates single field against the data dictionary
        s0, = M.proc("CHK^DIE", self.fileid, self.fieldid, "H", value,
                     M.INOUT(""), "ERR")

        err = M.Globals["ERR"]

        # s0 should contain ^ for error, internal value for valid data
        if s0 == "^":
            error_code = err['DIERR'][1].value
            error_msg = '\n'.join(
                [v for k, v in err['DIERR'][1]['TEXT'].items()])
            help_msg = [v for k, v in err['DIHELP'].items()]

            raise FilemanError(
                """DBSDD.fm_validate_insert(): fileid = [%s], fieldid = [%s], value = [%s], error_code = [%s], error_msg = [%s], help = [%s]"""
                % (self.fileid, self.fieldid, value, error_code, error_msg,
                   help_msg))

        # If err exists, then some form of programming error
        if err.exists():
            raise FilemanError(
                """DBSDD.fm_validate_insert(): fileid = [%s], fieldid = [%s], value = [%s], err = [%s]"""
                % (self.fileid, self.fieldid, value, '\n'.join(err)))
示例#2
0
文件: dbsdd.py 项目: whitten/vavista
 def fileid(self):
     """
         Look up the ^DIC array and find the file number for the specified file, 
         e.g. FILE = 1 - result is a string.
     """
     if self._fileid is None:
         rv = M.mexec('''set s1=$order(^DIC("B",s0,0))''',
                      str(self.filename[:30]), M.INOUT(""))[0]
         if rv != '':
             self._fileid = rv
     return self._fileid
示例#3
0
    def list_files(self):
        """
            Oddly, I cannot see how to list the files using the DBS API.
            This is required for debugging etc.
        """
        if self.remote:
            return self.remote.list_files()

        M.mset('DUZ',self.DUZ)
        M.mset('U', "^")
        if self.isProgrammer:
            M.mset('DUZ(0)', "@")
        rv = []
        s0 = "0"
        while s0 != "":
            s0, name = M.mexec(
                '''set s0=$order(^DIC(s0)) Q:s0'=+s0  I $D(^DIC(s0,0))&$D(^DIC(s0,0,"GL"))&$$VFILE^DILFD(s0) S s1=$P(^DIC(s0,0),U,1)''',
                M.INOUT(s0), M.INOUT(""))
            if name:
                rv.append((name, s0))
        return rv
示例#4
0
    def next(self):
        lastkey = self.lastkey
        lastrowid = self.lastrowid
        if self.ascending:
            asc = 1
        else:
            asc = -1

        # TODO: Fileman seems to structure indices with keys in the global path
        #       or in the value - need to investigate further

        # There is a mad collation approach in M, where numbers sort before non-numbers.
        # this really messes up the keys.
        # How should I search?

        # There is an inefficiency here it takes three searches to find the next record.
        while 1:
            if lastrowid is None:
                # locate the next matching index value
                lastkey, = M.mexec(
                    """set s0=$order(%ss0),%s)""" % (self.gl, asc),
                    M.INOUT(str(lastkey)))
                if lastkey == "":
                    break

                if self.ascending:
                    if self.from_value is not None:
                        if self.from_rule == ">" and lastkey <= self.from_value:
                            continue
                        if self.from_rule == ">=" and lastkey < self.from_value:
                            assert 0
                    if self.to_value is not None:
                        if self.to_rule == "<=" and lastkey > self.to_value:
                            break
                        if self.to_rule == "=" and lastkey != self.to_value:
                            break
                        if self.to_rule == "<" and lastkey >= self.to_value:
                            break
                    self.lastkey = lastkey
                    lastrowid = "0"

                else:  # descending
                    if self.from_value is not None:
                        if self.from_rule == "<" and lastkey >= self.from_value:
                            continue
                        if self.from_rule == "<=" and lastkey > self.from_value:
                            assert 0
                    if self.to_value is not None:
                        if self.to_rule == ">=" and lastkey < self.to_value:
                            break
                        if self.to_rule == "=" and lastkey != self.to_value:
                            break
                        if self.to_rule == ">" and lastkey <= self.to_value:
                            break
                    self.lastkey = lastkey
                    lastrowid = ""

            # Have the key, get the first matching rowid
            lastrowid, = M.mexec(
                """set s0=$order(%s"%s",s1),%d)""" %
                (self.gl, self.lastkey, asc), M.INOUT(str(lastkey)), lastrowid)
            if lastrowid == "":
                # No match
                lastrowid = None
                continue

            if self.filters:
                # Are filters to be applied?
                if not self.filters(lastrowid):
                    continue

            if self.skip_rows > 0:
                self.skip_rows -= 1
                continue

            self.lastrowid = lastrowid
            if self.raw:
                return self.lastkey, self.lastrowid
            return self.getter(self.lastrowid)

        raise StopIteration
示例#5
0
    def next(self):

        # Have we exceeded limit
        if self.limit and self.results_returned >= self.limit:
            raise StopIteration

        lastrowid = self.lastrowid  # This value should be a string throughout.
        if self.ascending:
            asc = 1
        else:
            asc = -1

        while not self.results_complete:
            # If this is the first pass, we may have the id of a record, which needs to
            # be verified
            found = False
            if self.first_pass:
                self.first_pass = False
                if lastrowid is None and asc == -1:
                    lastrowid, = M.mexec(
                        """set s0=$order(%ss0),-1)""" % self.gl, M.INOUT('%'))
                    if valid_rowid(lastrowid):
                        found = True
                elif lastrowid and float(lastrowid) > 0:
                    row_exists, = M.mexec(
                        """set s0=$data(%ss0))""" % (self.gl),
                        M.INOUT(lastrowid))
                    if valid_rowid(row_exists):
                        found = True

            if not found:
                lastrowid, = M.mexec(
                    """set s0=$order(%ss0),%d)""" % (self.gl, asc),
                    M.INOUT(lastrowid))
                if not valid_rowid(lastrowid):
                    break

            # Check boundary values
            f_lastrowid = float(lastrowid)
            if self.ascending:
                if self.from_rowid is not None:
                    if f_lastrowid == self.from_rowid and self.from_rule == ">":
                        continue
                if self.to_rowid is not None:
                    if f_lastrowid >= self.to_rowid and self.to_rule == "<":
                        break
                    if f_lastrowid > self.to_rowid and self.to_rule == "<=":
                        break
            else:  # descending:
                if f_lastrowid == 0:
                    break  # header record
                if self.from_rowid is not None:
                    if f_lastrowid == self.from_rowid and self.from_rule == "<":
                        continue
                if self.to_rowid is not None:
                    if f_lastrowid <= self.to_rowid and self.to_rule == ">":
                        break
                    if f_lastrowid < self.to_rowid and self.to_rule == ">=":
                        break

            if self.filters:
                # Are filters to be applied?
                if not self.filters(lastrowid):
                    continue

            if self.skip_rows > 0:
                self.skip_rows -= 1
                continue

            self.lastrowid = lastrowid

            self.results_returned += 1

            if self.raw:
                return self.lastrowid
            return self.getter(self.lastrowid)

        self.results_complete = True
        raise StopIteration
示例#6
0
文件: dbsdd.py 项目: whitten/vavista
    def indices(self):
        """
            Return a list of the indices

            To be valid, the index must be both in the IX

            ^DD(200,0,"IX","AASWB",200,654)=""

        """
        if self._indices is None:
            i = []

            # TODO: this is not right for multi-column keys
            # TODO: new style indexes

            global_name = '^DD(%s,0,"IX","0")' % self.fileid
            prefix = '^DD(%s,0,"IX",' % self.fileid
            while 1:
                global_name = M.mexec('set s0=$query(%s)' % global_name,
                                      M.INOUT(""))[0]
                if not global_name or not global_name.startswith(prefix):
                    break
                suffix = global_name[len(prefix):-1]
                parts = suffix.split(",")
                idx_name = parts[0][1:-1]
                idx_table = parts[1]
                idx_columns = parts[2:]
                index = Index(idx_name, idx_table, idx_columns)
                i.append(index)

            # A second list, gives indices for a field
            columns = {}
            for idx in i:
                for c in idx.columns:
                    columns[c] = 1

            # Now trawl the listed columns in the data dictionary, and load their
            # cross references.
            cr_names = {}
            for c in columns.keys():
                idx_root = M.Globals["^DD"][self.fileid][c][1]
                if not idx_root[0].exists():
                    continue
                for cr_id, val in idx_root.keys_with_decendants():
                    if float(cr_id) > 0:
                        cr_header = idx_root[cr_id][0].value
                        parts = cr_header.split("^")
                        if len(parts) == 2 and parts[
                                1]:  # if more than 2 parts, assume MUMPs trigger
                            f = cr_names.get(parts[1], list())
                            f.append(c)
                            cr_names[parts[1]] = f

            # Now, just delete items from the index list if they are not in cr_names
            self._indices = []
            for index in i:
                cr = cr_names.get(index.name)
                if cr:
                    # verify columns - lots of errors in real systems
                    if len(cr) == len(index.columns):
                        invalid = False
                        for c in cr:
                            if c not in index.columns:
                                invalid = True
                                continue
                        if not invalid:
                            self._indices.append(index)

        return self._indices
示例#7
0
def index_order_traversal(gl_prefix,
                          index,
                          ranges=None,
                          ascending=True,
                          sf_path=[],
                          explain=False):
    """
        A generator which will traverse an index.
        The iterator should yield rowids.

            Indices are stored:
                GLOBAL,INDEXID,VALUE,ROWID=""
            ^DIZ(999900,"B","hello there from unit test2",183)=""
            ^DIZ(999900,"B","hello there from unit test2",184)=""
            ^DIZ(999900,"B","hello there from unit test2",185)=""
            ^DIZ(999900,"B","record 1",1)=""

    """
    gl = gl_prefix + '"%s",' % index

    if ranges:
        r = ranges[0]
        from_value = r['from_value']
        to_value = r['to_value']
        from_rule = r['from_rule']
        to_rule = r['to_rule']
    else:
        from_value, to_value, from_rule, to_rule = None, None, None, None

    if explain:
        yield "index_order_traversal, ascending=%s, gl=%s, index=%s, X %s '%s' AND X %s '%s'" % (
            ascending, gl, index, from_rule, from_value, to_rule, to_value)
        return

    if from_value != None and to_value != None:
        if ascending:
            assert (from_value <= to_value)
        else:
            assert (to_value <= from_value)

    if from_value is None:
        if ascending:
            lastkey = " "
        else:
            lastkey = "ZZZZZZZZZZZZZZ"
        lastrowid = ""
    else:
        lastkey = from_value
        if from_rule == '>':
            lastrowid = None  # looks for the next key after lastkey
        else:
            lastrowid = ''  # looks for the lastkey

    if ascending:
        asc = 1
    else:
        asc = -1

    # TODO: Fileman seems to structure indices with keys in the global path
    #       or in the value - need to investigate further

    # There is a mad collation approach in M, where numbers sort before non-numbers.
    # this really messes up the keys.
    # How should I search?

    # There is an inefficiency here it takes three searches to find the next record.
    while 1:
        if lastrowid is None:
            # locate the next matching index value
            lastkey, = M.mexec("""set s0=$order(%ss0),%s)""" % (gl, asc),
                               M.INOUT(str(lastkey)))
            if lastkey == "":
                break

            if ascending:
                if from_value is not None:
                    if from_rule == ">" and lastkey <= from_value:
                        continue
                    if from_rule == ">=" and lastkey < from_value:
                        assert 0
                if to_value is not None:
                    if to_rule == "<=" and lastkey > to_value:
                        break
                    if to_rule == "=" and lastkey != to_value:
                        break
                    if to_rule == "<" and lastkey >= to_value:
                        break
                lastkey = lastkey
                lastrowid = "0"

            else:  # descending
                if from_value is not None:
                    if from_rule == "<" and lastkey >= from_value:
                        continue
                    if from_rule == "<=" and lastkey > from_value:
                        assert 0
                if to_value is not None:
                    if to_rule == ">=" and lastkey < to_value:
                        break
                    if to_rule == "=" and lastkey != to_value:
                        break
                    if to_rule == ">" and lastkey <= to_value:
                        break
                lastkey = lastkey
                lastrowid = ""

        # Have the key, get the first matching rowid
        lastrowid, = M.mexec(
            """set s0=$order(%s"%s",s1),%d)""" % (gl, lastkey, asc),
            M.INOUT(str(lastkey)), lastrowid)
        if lastrowid == "":
            # No match
            lastrowid = None
            continue

        yield (lastrowid, "%s%s)" % (gl_prefix, lastrowid),
               sf_path + [lastrowid])
示例#8
0
def file_order_traversal(gl,
                         ranges=None,
                         ascending=True,
                         sf_path=[],
                         explain=False):
    """
        Originate records by traversing the file in file order (i.e. no index)
    """
    if ranges:
        r = ranges[0]
        from_rowid = r['from_value']
        to_rowid = r['to_value']
        from_rule = r['from_rule']
        to_rule = r['to_rule']
    else:
        from_rowid, to_rowid, from_rule, to_rule = None, None, None, None

    if explain:
        yield "file_order_traversal, ascending=%s, gl=%s, X %s %s AND X %s %s" % (
            ascending, gl, from_rule, from_rowid, to_rule, to_rowid)
        return

    # the new person file has non-integer user ids
    if from_rowid != None:
        from_rowid = float(from_rowid)
    if to_rowid != None:
        to_rowid = float(to_rowid)

    if from_rowid != None and to_rowid != None:
        if ascending:
            assert (from_rowid <= to_rowid)
        else:
            assert (to_rowid <= from_rowid)

    if from_rowid is None:
        if ascending:
            lastrowid = "0"
        else:
            lastrowid = None
    else:
        # TODO: I have this in code in shared
        lastrowid = ('%f' % from_rowid).rstrip('0').rstrip('.').lstrip('0')
        if from_rowid > 0 and lastrowid[0] == "0":
            lastrowid = lastrowid[1:]
        if lastrowid.endswith(".0"):
            lastrowid = lastrowid[:-2]

    first_pass = True

    if ascending:
        asc = 1
    else:
        asc = -1

    while 1:
        # If this is the first pass, we may have the id of a record, which needs to
        # be verified
        found = False
        if first_pass:
            first_pass = False
            if lastrowid is None and asc == -1:
                lastrowid, = M.mexec("""set s0=$order(%ss0),-1)""" % gl,
                                     M.INOUT('%'))
                if valid_rowid(lastrowid):
                    found = True
            elif lastrowid and float(lastrowid) > 0:
                row_exists, = M.mexec("""set s0=$data(%ss0))""" % (gl),
                                      M.INOUT(lastrowid))
                if valid_rowid(row_exists):
                    found = True

        if not found:
            lastrowid, = M.mexec("""set s0=$order(%ss0),%d)""" % (gl, asc),
                                 M.INOUT(lastrowid))
            if not valid_rowid(lastrowid):
                break

        # Check boundary values
        f_lastrowid = float(lastrowid)
        if ascending:
            if from_rowid is not None:
                if f_lastrowid == from_rowid and from_rule == ">":
                    continue
            if to_rowid is not None:
                if f_lastrowid >= to_rowid and to_rule == "<":
                    break
                if f_lastrowid > to_rowid and to_rule == "<=":
                    break
        else:  # descending:
            if f_lastrowid == 0:
                break  # header record
            if from_rowid is not None:
                if f_lastrowid == from_rowid and from_rule == "<":
                    continue
            if to_rowid is not None:
                if f_lastrowid <= to_rowid and to_rule == ">":
                    break
                if f_lastrowid < to_rowid and to_rule == ">=":
                    break

        # If this is a subfile, I need to return the full path.
        yield (lastrowid, "%s%s)" % (gl, lastrowid), sf_path + [lastrowid])