1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19  import time 
 20  import string 
 21   
 22  from UserDict import UserDict 
 23  from spacewalk.common.usix import ListType, StringType, DictType, IntType, UnicodeType 
 24   
 25   
 26   
 27   
 30   
 31   
 34   
 35   
 38   
 39   
 40   
 41   
 44   
 45   
 48   
 49   
 54   
 55   
 58   
 59   
 62   
 63   
 66   
 67   
 68   
 69   
 71       
 72      keywords = { 
 73          'fields': DictType, 
 74          'pk': ListType, 
 75          'attribute': StringType, 
 76          'map': DictType, 
 77          'nullable': ListType,   
 78          'severityHash': DictType, 
 79          'defaultSeverity': IntType, 
 80          'sequenceColumn': StringType, 
 81      } 
 82   
 84          self.name = name 
 85          for k in kwargs.keys(): 
 86              if k not in self.keywords: 
 87                  raise TypeError("Unknown keyword attribute '%s'" % k) 
 88           
 89           
 90          self.fields = {} 
 91           
 92          self.pk = [] 
 93           
 94          self.map = {} 
 95           
 96          self.attribute = None 
 97           
 98          self.nullable = [] 
 99           
100          self.severityHash = {} 
101          self.defaultSeverity = 4 
102           
103          self.sequenceColumn = None 
104   
105          for k, v in kwargs.items(): 
106              datatype = self.keywords[k] 
107              if not isinstance(v, datatype): 
108                  raise TypeError("%s expected to be %s; got %s" % ( 
109                      k, datatype, type(v))) 
110              setattr(self, k, v) 
111   
112           
113          nullable = self.nullable 
114          self.nullable = {} 
115          if nullable: 
116              for field in nullable: 
117                  if field not in self.fields: 
118                      raise TypeError("Unknown nullable field %s in table %s" % ( 
119                          field, name)) 
120                  self.nullable[field] = None 
121   
122           
123          for field in self.pk: 
124              if field not in self.fields: 
125                  raise TypeError("Unknown primary key field %s" % field) 
 126   
128          return "Instance of class %s.%s: PK: %s, Fields: %s" % (self.__class__.__module__, 
129                                                                  self.__class__.__name__, self.pk, self.fields) 
 130      __repr__ = __str__ 
131   
133          if field not in self.fields: 
134              raise TypeError("Unknown field %s" % field) 
135          return field in self.nullable 
 136   
139   
142   
144          return self.attribute 
 145   
147          if attribute in self.map: 
148              return self.map[attribute] 
149          return attribute 
 150   
152          for field in self.fields.keys(): 
153              if field not in self.severityHash: 
154                  self.severityHash[field] = self.defaultSeverity 
155          return self.severityHash 
  156   
157   
158   
159   
172   
173   
174   
175   
176   
177   
179   
189   
191           
192          keys = [[]] 
193           
194          queries = [[]] 
195          for col in self.pks: 
196              k = [] 
197              q = [] 
198              for i in range(len(keys)): 
199                  key = keys[i] 
200                  query = queries[i] 
201                  k.append(key + [0]) 
202                  q.append(query + ["%s = :%s" % (col, col)]) 
203                  if self.table.isNullable(col): 
204                      k.append(key + [1]) 
205                      q.append(query + ["%s is null" % col]) 
206              keys = k 
207              queries = q 
208           
209          for i in range(len(keys)): 
210              key = tuple(keys[i]) 
211              query = string.join(queries[i], ' and ') 
212              self.whereclauses[key] = query 
 213   
215           
216           
217          hash = {} 
218          key = [] 
219          for col in self.pks: 
220              if self.table.isNullable(col) and value[col] in [None, '']: 
221                  key.append(1) 
222              else: 
223                  key.append(0) 
224                  hash[col] = value[col] 
225          key = tuple(key) 
226          return key, hash 
 227   
231   
233          if key in self.queries: 
234               
235              return self.queries[key] 
236   
237          statement = self.dbmodule.prepare(self._buildQuery(key), blob_map=blob_map) 
238           
239          self.queries[key] = statement 
240          return statement 
 241   
242 -    def query(self, values): 
  247   
248   
250   
254   
256          return self.queryTemplate % (self.table.name, self.whereclauses[key]) 
  257   
258   
260   
262          BaseTableLookup.__init__(self, table, dbmodule) 
263          self.queryTemplate = "update %s set %s where %s" 
264          self.fields = list(self.table.getFields().keys()) 
265          self.count = 1000 
266           
267          self.otherfields = [] 
268           
269          self.blob_fields = [] 
270          for field in self.fields: 
271              if field in self.pks: 
272                  continue 
273              datatype = self.table.fields[field] 
274              if isinstance(datatype, DBblob): 
275                  self.blob_fields.append(field) 
276              else: 
277                  self.otherfields.append(field) 
278          self.updateclause = string.join( 
279              ["%s = :%s" % (x, x) for x in self.otherfields], ', ') 
280           
281          self.firstkey = None 
282          for pk in self.pks: 
283              if not self.table.isNullable(pk): 
284                   
285                  self.firstkey = pk 
286                  break 
 287   
289          return self.queryTemplate % (self.table.name, self.updateclause, 
290                                       self.whereclauses[key]) 
 291   
293           
294           
295          valuesHash = {} 
296           
297           
298           
299          blobValuesHash = {} 
300          for key in self.whereclauses.keys(): 
301              hash = {} 
302              for i in range(len(key)): 
303                  pk = self.pks[i] 
304                   
305                  if not key[i]: 
306                      hash[pk] = [] 
307               
308              for k in self.otherfields: 
309                  hash[k] = [] 
310              valuesHash[key] = hash 
311              blobValuesHash[key] = [] 
312   
313           
314          for i in range(len(values[self.firstkey])): 
315               
316              pk_val = {} 
317              val = {} 
318              for k in self.pks: 
319                  pk_val[k] = val[k] = values[k][i] 
320              key, val = self._selectQueryKey(val) 
321   
322              if not blob_only: 
323                   
324                  for k in self.otherfields: 
325                      val[k] = values[k][i] 
326                  addHash(valuesHash[key], val) 
327   
328              if not self.blob_fields: 
329                   
330                  continue 
331              val = {} 
332              for k in self.blob_fields: 
333                  val[k] = values[k][i] 
334              blobValuesHash[key].append((pk_val, val)) 
335   
336          return valuesHash, blobValuesHash 
 337   
338 -    def query(self, values): 
 339          valuesHash, blobValuesHash = self._split_blob_values(values, blob_only=0) 
340           
341          if self.otherfields: 
342              for key, val in valuesHash.items(): 
343                  if not val[self.firstkey]: 
344                       
345                      continue 
346                  statement = self._getCachedQuery(key) 
347                  executeStatement(statement, val, self.count) 
348   
349          if not self.blob_fields: 
350              return 
351   
352          self._update_blobs(blobValuesHash) 
 353   
355           
356          template = "select %s from %s where %s for update" 
357          blob_fields_string = string.join(self.blob_fields, ", ") 
358          for key, val in blobValuesHash.items(): 
359              statement = template % (blob_fields_string, self.table.name, 
360                                      self.whereclauses[key]) 
361              h = self.dbmodule.prepare(statement) 
362              for lookup_hash, blob_hash in val: 
363                  h.execute(**lookup_hash) 
364                   
365                  row = h.fetchone_dict() 
366                  if not row: 
367                       
368                      raise ValueError("BLOB query did not retrieve a value") 
369                  for k, v in blob_hash.items(): 
370                      blob = row[k] 
371                      len_v = len(v) 
372                       
373                       
374                      if blob.size() > len_v: 
375                          blob.trim(len_v) 
376                       
377                      if len_v: 
378                          blob.write(v) 
379                   
380                  row = h.fetchone_dict() 
381                  if row is not None: 
382                       
383                       
384                      raise ValueError("Primary key not unique", 
385                                       self.table.name, lookup_hash) 
  386   
387   
389   
391          TableLookup.__init__(self, table, dbmodule) 
392          self.queryTemplate = "delete from %s where %s" 
393          self.count = 1000 
 394   
395 -    def query(self, values): 
 396           
397          valuesHash = {} 
398          for key in self.whereclauses.keys(): 
399              hash = {} 
400              for i in range(len(key)): 
401                  pk = self.pks[i] 
402                   
403                  if not key[i]: 
404                      hash[pk] = [] 
405              valuesHash[key] = hash 
406   
407           
408          firstkey = self.pks[0] 
409          for i in range(len(values[firstkey])): 
410               
411              val = {} 
412              for k in self.pks: 
413                  val[k] = values[k][i] 
414              key, val = self._selectQueryKey(val) 
415              addHash(valuesHash[key], val) 
416   
417           
418          for key, val in valuesHash.items(): 
419              firstkey = val.keys()[0] 
420              if not val[firstkey]: 
421                   
422                  continue 
423              statement = self._getCachedQuery(key) 
424              executeStatement(statement, val, self.count) 
  425   
426   
428   
430          TableUpdate.__init__(self, table, dbmodule) 
431          self.queryTemplate = "insert into %s (%s) values (%s)" 
432          self.count = 1000 
433   
434          self.insert_fields = self.pks + self.otherfields + self.blob_fields 
435          self.insert_values = [':%s' % x for x in self.pks + self.otherfields + self.blob_fields] 
 436   
438          q = self.queryTemplate % (self.table.name, 
439                                    string.join(self.insert_fields, ', '), 
440                                    string.join(self.insert_values, ', ')) 
441          return q 
 442   
443 -    def query(self, values): 
 444          if self.blob_fields: 
445              chunksize = 1 
446              blob_map = {} 
447              for f in self.blob_fields: 
448                  blob_map[f] = f 
449          else: 
450              chunksize = self.count 
451              blob_map = None 
452   
453           
454          statement = self._getCachedQuery(None, blob_map=blob_map) 
455          executeStatement(statement, values, chunksize) 
  456   
457   
459       
460      if not valuesHash: 
461           
462          return 
463      count = 0 
464      while 1: 
465          tempdict = {} 
466          for k, vals in valuesHash.items(): 
467              if not vals: 
468                   
469                  break 
470              if chunksize > 1: 
471                  tempdict[k] = vals[:chunksize] 
472              else: 
473                  tempdict[k] = vals[0] 
474              del vals[:chunksize] 
475          if not tempdict: 
476               
477              break 
478           
479          if chunksize > 1: 
480              count += statement.executemany(**tempdict) 
481          else: 
482              count += statement.execute(**tempdict) 
483      return count 
 484   
485   
487      if isinstance(datatype, DBstring): 
488          if value is None or value == '': 
489              return None          
490               
491               
492               
493          elif isinstance(value, UnicodeType): 
494              value = UnicodeType.encode(value, 'utf-8') 
495          if len(value) > datatype.limit: 
496              value = value[:datatype.limit] 
497               
498              value = value.decode('utf-8', 'ignore') 
499              value = value.encode('utf-8') 
500          return value 
501      if isinstance(datatype, DBblob): 
502          if value is None: 
503              value = '' 
504          if isinstance(value, UnicodeType): 
505              value = UnicodeType.encode(value, 'utf-8') 
506          return str(value) 
507      if value in [None, '']: 
508          return None 
509      if isinstance(datatype, DBdateTime): 
510          s = str(value) 
511          if len(s) == 10: 
512               
513              s = s + " 00:00:00" 
514          return s 
515      if isinstance(datatype, DBdate): 
516          return str(value)[:10] 
517      if isinstance(datatype, DBint): 
518          return int(value) 
519      return value 
 520   
521   
523       
524       
525      for k, v in hash.items(): 
526          if k in hasharray: 
527              hasharray[k].append(v) 
 528