1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
40
41
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
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
75
78
79
80
81
84
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
106 self._query = query
107
108 self._has_output = self._is_select()
109
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
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
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
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
149
151
152
153 self._execute_query([])
154
155
156
158 self._execute_query(object)
159
161 self._connection.close()
162 self.send_complete()
163
164
165
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
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
191
192 - def connect(self, db, host, user, password):
194
195 - def run_query(self, connection, query, inputs):
197
200
203