Package osh :: Package command :: Module sql
[frames] | no frames]

Source Code for Module osh.command.sql

  1  # osh 
  2  # Copyright (C) Jack Orenstein <jao@geophile.com> 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or 
  7  # (at your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 12  # GNU General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 17   
 18  """C{sql [DB] QUERY} 
 19   
 20  Executes a sql query on a specified database.  Occurrences of 
 21  formatting directives (e.g. C{%s}) will be replaced by input values. 
 22   
 23  The database is selected by C{DB}. If C{DB} matches an C{osh.sql} 
 24  profile in C{.oshrc}, then the database is specified by that 
 25  profile. If C{DB} is omitted, then the default profile is used. 
 26   
 27  If C{QUERY} is a I{select} statement, then the query is executed and 
 28  output rows, represented by tuples, are written to output.  If C{QUERY} 
 29  is any other type of SQL statement, then no output is written. 
 30  """ 
 31   
 32  import os 
 33   
 34  import osh.loader 
 35  import osh.core 
 36   
 37  # CLI 
38 -def _sql():
39 return _Sql()
40 41 # CLI
42 -def sql(query, db = None):
43 """Executes a sql query on a specified database. Occurrences of 44 formatting directives (e.g. C{%s}) will be replaced by input values. 45 The database is selected by C{db}. If C{db} matches an C{osh.sql} 46 profile in C{.oshrc}, then the database is specified by that 47 profile. If C{db} is C{None}, then the default profile is used. 48 If C{QUERY} is a I{select} statement, then the query is executed and 49 output rows, represented by tuples, are written to output. If C{QUERY} 50 is any other type of SQL statement, then no output is written. 51 """ 52 args = [] 53 if db: 54 args.append(db) 55 args.append(query) 56 return _Sql().process_args(*args)
57
58 -def _tuple_like(object):
59 return isinstance(object, list) or isinstance(object, tuple)
60
61 -class _Sql(osh.core.Generator):
62 63 _db_type = None 64 _host = None 65 _db = None 66 _header = None 67 _user = None 68 _password = None 69 _connection = None 70 _query = None 71 _has_output = None 72 73 74 # object interface 75
76 - def __init__(self):
77 osh.core.Generator.__init__(self, '', (1, 2))
78 79 80 # OshCommand interface 81
82 - def doc(self):
83 return __doc__
84
85 - def setup(self):
86 args = self.args() 87 db_profile = None 88 if args.has_next(): 89 query = args.next_string() 90 if args.has_next(): 91 db_profile = query 92 query = args.next_string() 93 if args.has_next(): 94 self.usage() 95 else: 96 self.usage() 97 if not db_profile: 98 db_profile_from_env = osh.core.default_db_profile 99 if db_profile_from_env: 100 db_profile = db_profile_from_env 101 else: 102 db_profile = osh.core.config_value('sql') 103 if not db_profile: 104 raise Exception('No db profile selected') 105 # query 106 self._query = query 107 # query type 108 self._has_output = self._is_select() 109 # schema 110 if self.thread_state and type(self.thread_state) is osh.cluster.Host: 111 schema = self.thread_state.schema 112 else: 113 schema = None 114 # connection info 115 driver = osh.core.config_value('sql', db_profile, 'driver') 116 dbtype = osh.core.config_value('sql', db_profile, 'dbtype') 117 if dbtype is None and driver is None: 118 raise Exception('Database configuration osh.sql.%s must configure either dbtype or driver' % 119 db_profile) 120 elif driver: 121 connect_info = osh.core.config_subset('sql.%s' % db_profile) 122 # Make sure set_schema specification is gone for establishing connection 123 try: 124 del connect_info['set_schema'] 125 except KeyError: 126 pass 127 import sqladapter.dbapi 128 self._db_type = sqladapter.dbapi.DBAPI() 129 self._connection = self._db_type.connect(connect_info) 130 elif dbtype: 131 host = osh.core.config_value('sql', db_profile, 'host') 132 if host is None: 133 host = 'localhost' 134 db = osh.core.config_value('sql', db_profile, 'db') 135 user = osh.core.config_value('sql', db_profile, 'user') 136 password = osh.core.config_value('sql', db_profile, 'password') 137 # Load dbtype module and connect 138 self._db_type = osh.loader.load_and_create(dbtype) 139 self._connection = self._db_type.connect(db, host, user, password) 140 else: 141 assert False 142 set_schema_query = osh.core.config_value('sql', db_profile, 'set_schema') 143 if set_schema_query and self.thread_state: 144 schema = self.thread_state.schema 145 self._db_type.run_update(self._connection, set_schema_query % schema, [])
146 147 148 # Generator interface 149
150 - def execute(self):
151 # If this command is the first in a pipeline, then execute will be 152 # called. 153 self._execute_query([])
154 155 # Receiver interface 156
157 - def receive(self, object):
158 self._execute_query(object)
159
160 - def receive_complete(self):
161 self._connection.close() 162 self.send_complete()
163 164 # For use by this class 165
166 - def _execute_query(self, inputs):
167 if self._has_output: 168 for row in self._db_type.run_query(self._connection, self._query, inputs): 169 self.send(row) 170 else: 171 self.send(self._db_type.run_update(self._connection, self._query, inputs))
172
173 - def _is_select(self):
174 query = self._query.lower() 175 select_position = self._find(query, 'select') 176 insert_position = self._find(query, 'insert') 177 update_position = self._find(query, 'update') 178 delete_position = self._find(query, 'delete') 179 return (select_position < len(query) and 180 select_position < insert_position and 181 select_position < update_position and 182 select_position < delete_position)
183
184 - def _find(self, string, substring):
185 position = string.find(substring) 186 if position == -1: 187 position = len(string) 188 return position
189
190 -class _DBType(object):
191
192 - def connect(self, db, host, user, password):
193 assert False
194
195 - def run_query(self, connection, query, inputs):
196 assert False
197
198 - def run_update(self, connection, query, inputs):
199 assert False
200
201 - def close_connection(self, connection):
202 assert False
203