pg.py
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:7k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. # pgutil.py
  2. # Written by D'Arcy J.M. Cain
  3. # This library implements some basic database management stuff
  4. # It includes the pg module and builds on it
  5. from _pg import *
  6. import string, re, sys
  7. # utility function
  8. # We expect int, seq, decimal, text or date (more later)
  9. def _quote(d, t):
  10. if t in ['int', 'decimal', 'seq']:
  11. if d == "": return 0
  12. return "%s" % d
  13. if t == 'money':
  14. if d == "": return '0.00'
  15. return "'%.2f'" % d
  16. if t == 'bool':
  17. if string.upper(d) in ['T', 'TRUE', 'Y', 'YES', 1, '1', 'ON']:
  18. return "'t'"
  19. else:
  20. return "'f'"
  21. if d == "": return "null"
  22. return "'%s'" % string.strip(re.sub("'", "''", "%s" % d))
  23. class DB:
  24. """This class wraps the pg connection type"""
  25. def __init__(self, *args, **kw):
  26. self.db = apply(connect, args, kw)
  27. # Create convience methods, in a way that is still overridable.
  28. for e in ( 'query', 'reset', 'close', 'getnotify', 'inserttable',
  29. 'putline', 'getline', 'endcopy',
  30. 'host', 'port', 'db', 'options', 
  31. 'tty', 'error', 'status', 'user',
  32. 'locreate', 'getlo', 'loimport' ):
  33. if not hasattr(self,e) and hasattr(self.db,e):
  34. exec 'self.%s = self.db.%s' % ( e, e )
  35. self.attnames = {}
  36. self.pkeys = {}
  37. self.debug = None # For debugging scripts, set to output format
  38. # that takes a single string arg.  For example
  39. # in a CGI set to "%s<BR>"
  40. # Get all the primary keys at once
  41. for rel, att in self.db.query("""SELECT
  42. pg_class.relname, pg_attribute.attname
  43. FROM pg_class, pg_attribute, pg_index
  44. WHERE pg_class.oid = pg_attribute.attrelid AND
  45. pg_class.oid = pg_index.indrelid AND
  46. pg_index.indkey[0] = pg_attribute.attnum AND 
  47. pg_index.indisprimary = 't'""").getresult():
  48. self.pkeys[rel] = att
  49. def pkey(self, cl):
  50. # will raise an exception if primary key doesn't exist
  51. return self.pkeys[cl]
  52. def get_databases(self):
  53. l = []
  54. for n in self.db.query("SELECT datname FROM pg_database").getresult():
  55. l.append(n[0])
  56. return l
  57. def get_tables(self):
  58. l = []
  59. for n in self.db.query("""SELECT relname FROM pg_class
  60. WHERE relkind = 'r' AND
  61. relname !~ '^Inv' AND
  62. relname !~ '^pg_'""").getresult():
  63. l.append(n[0])
  64. return l
  65. def get_attnames(self, cl):
  66. # May as well cache them
  67. if self.attnames.has_key(cl):
  68. return self.attnames[cl]
  69. query = """SELECT pg_attribute.attname, pg_type.typname
  70. FROM pg_class, pg_attribute, pg_type
  71. WHERE pg_class.relname = '%s' AND
  72. pg_attribute.attnum > 0 AND
  73. pg_attribute.attrelid = pg_class.oid AND
  74. pg_attribute.atttypid = pg_type.oid"""
  75. l = {}
  76. for attname, typname in self.db.query(query % cl).getresult():
  77. if re.match("^int", typname):
  78. l[attname] = 'int'
  79. elif re.match("^oid", typname):
  80. l[attname] = 'int'
  81. elif re.match("^text", typname):
  82. l[attname] = 'text'
  83. elif re.match("^char", typname):
  84. l[attname] = 'text'
  85. elif re.match("^name", typname):
  86. l[attname] = 'text'
  87. elif re.match("^abstime", typname):
  88. l[attname] = 'date'
  89. elif re.match("^date", typname):
  90. l[attname] = 'date'
  91. elif re.match("^bool", typname):
  92. l[attname] = 'bool'
  93. elif re.match("^float", typname):
  94. l[attname] = 'decimal'
  95. elif re.match("^money", typname):
  96. l[attname] = 'money'
  97. else:
  98. l[attname] = 'text'
  99. self.attnames[cl] = l
  100. return self.attnames[cl]
  101. # return a tuple from a database
  102. def get(self, cl, arg, keyname = None):
  103. if keyname == None: # use the primary key by default
  104. keyname = self.pkeys[cl]
  105. fnames = self.get_attnames(cl)
  106. if type(arg) == type({}):
  107. # To allow users to work with multiple tables we munge the
  108. # name when the key is "oid"
  109. if keyname == 'oid': k = arg['oid_%s' % cl]
  110. else: k = arg[keyname]
  111. else:
  112. k = arg
  113. arg = {}
  114. # We want the oid for later updates if that isn't the key
  115. if keyname == 'oid':
  116. q = "SELECT * FROM %s WHERE oid = %s" % (cl, k)
  117. else:
  118. q = "SELECT oid AS oid_%s, %s FROM %s WHERE %s = %s" % 
  119. (cl, string.join(fnames.keys(), ','),
  120. cl, keyname, _quote(k, fnames[keyname]))
  121. if self.debug != None: print self.debug % q
  122. res = self.db.query(q).dictresult()
  123. if res == []:
  124. raise error, 
  125. "No such record in %s where %s is %s" % 
  126. (cl, keyname, _quote(k, fnames[keyname]))
  127. return None
  128. for k in res[0].keys():
  129. arg[k] = res[0][k]
  130. return arg
  131. # Inserts a new tuple into a table
  132. def insert(self, cl, a):
  133. fnames = self.get_attnames(cl)
  134. l = []
  135. n = []
  136. for f in fnames.keys():
  137. if a.has_key(f):
  138. if a[f] == "": l.append("null")
  139. else: l.append(_quote(a[f], fnames[f]))
  140. n.append(f)
  141. try:
  142. q = "INSERT INTO %s (%s) VALUES (%s)" % 
  143. (cl, string.join(n, ','), string.join(l, ','))
  144. if self.debug != None: print self.debug % q
  145. a['oid_%s' % cl] = self.db.query(q)
  146. except:
  147. raise error, "Error inserting into %s: %s" % (cl, sys.exc_value)
  148. # reload the dictionary to catch things modified by engine
  149. # note that get() changes 'oid' below to oid_table
  150. # if no read perms (it can and does happen) return None
  151. try: return self.get(cl, a, 'oid')
  152. except: return None
  153. # Update always works on the oid which get returns if available
  154. # otherwise use the primary key.  Fail if neither.
  155. def update(self, cl, a):
  156. foid = 'oid_%s' % cl
  157. pk = self.pkeys[cl]
  158. if a.has_key(foid):
  159. where = "oid = %s" % a[foid]
  160. elif a.has_key(pk):
  161. where = "%s = '%s'" % (pk, a[pk])
  162. else:
  163. raise error, "Update needs key (%s) or oid as %s" % (pk, foid)
  164. q = "SELECT oid FROM %s WHERE %s" % (cl, where)
  165. if self.debug != None: print self.debug % q
  166. res = self.db.query(q).getresult()
  167. if len(res) < 1:
  168. raise error,  "No record in %s where %s (%s)" % 
  169. (cl, where, sys.exc_value)
  170. else: a[foid] = res[0][0]
  171. v = []
  172. k = 0
  173. fnames = self.get_attnames(cl)
  174. for ff in fnames.keys():
  175. if a.has_key(ff) and a[ff] != res[0][k]:
  176. v.append("%s = %s" % (ff, _quote(a[ff], fnames[ff])))
  177. if v == []:
  178. return None
  179. try:
  180. q = "UPDATE %s SET %s WHERE oid = %s" % 
  181. (cl, string.join(v, ','), a[foid])
  182. if self.debug != None: print self.debug % q
  183. self.db.query(q)
  184. except:
  185. raise error, "Can't update %s: %s" % (cl, sys.exc_value)
  186. # reload the dictionary to catch things modified by engine
  187. return self.get(cl, a, 'oid')
  188. # At some point we will need a way to get defaults from a table
  189. def clear(self, cl, a = {}):
  190. fnames = self.get_attnames(cl)
  191. for ff in fnames.keys():
  192. if fnames[ff] in ['int', 'decimal', 'seq', 'money']:
  193. a[ff] = 0
  194. elif fnames[ff] == 'date':
  195. a[ff] = 'TODAY'
  196. else:
  197. a[ff] = ""
  198. a['oid'] = 0
  199. return a
  200. # Like update, delete works on the oid
  201. # one day we will be testing that the record to be deleted
  202. # isn't referenced somewhere (or else PostgreSQL will)
  203. def delete(self, cl, a):
  204. try:
  205. q = "DELETE FROM %s WHERE oid = %s" % (cl, a['oid_%s' % cl])
  206. if self.debug != None: print self.debug % q
  207. self.db.query(q)
  208. except:
  209. raise error, "Can't delete %s: %s" % (cl, sys.exc_value)
  210. return None