Merge lp:~clint-fewbar/drizzle/regex-policy-cache-limiter into lp:~drizzle-trunk/drizzle/development
- regex-policy-cache-limiter
- Merge into development
Status: | Merged |
---|---|
Merged at revision: | 2535 |
Proposed branch: | lp:~clint-fewbar/drizzle/regex-policy-cache-limiter |
Merge into: | lp:~drizzle-trunk/drizzle/development |
Diff against target: |
480 lines (+291/-42) 5 files modified
plugin/regex_policy/module.cc (+117/-33) plugin/regex_policy/policy.h (+30/-9) plugin/regex_policy/tests/r/cache_overflow.result (+73/-0) plugin/regex_policy/tests/t/cache_overflow-master.opt (+1/-0) plugin/regex_policy/tests/t/cache_overflow.test (+70/-0) |
To merge this branch: | bzr merge lp:~clint-fewbar/drizzle/regex-policy-cache-limiter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olaf van der Spek (community) | Needs Fixing | ||
Drizzle Developers | Pending | ||
Lee Bieber | Pending | ||
Review via email: mp+53536@code.launchpad.net |
This proposal supersedes a proposal from 2011-03-09.
Commit message
Description of the change
The version of regex_policy plugin in trunk will eat memory indefinitely, adding an item for every user+object combination ever checked. This adds a limit on the number of items the cache will hold.
Olaf van der Spek (olafvdspek) wrote : Posted in a previous version of this proposal | # |
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
Olaf.. can you share what it is?
%zu and %zd are both forbidden in ISO C++.
Olaf van der Spek (olafvdspek) wrote : Posted in a previous version of this proposal | # |
On Thu, Mar 10, 2011 at 6:34 PM, Clint Byrum <email address hidden> wrote:
> Olaf.. can you share what it is?
>
> %zu and %zd are both forbidden in ISO C++.
I was thinking about those two.
Monty Taylor (mordred) wrote : Posted in a previous version of this proposal | # |
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
Can we try one more time please?
Olaf van der Spek (olafvdspek) wrote : Posted in a previous version of this proposal | # |
194: lru.empty();
Should this be clear()?
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
On Fri, 2011-03-11 at 10:45 +0000, Olaf van der Spek wrote:
> 194: lru.empty();
> Should this be clear()?
Yes! good catch. The affect of this would have been poor performance
(the list is limited in size, but at this point in the code, its better
to have the list empty because the cache has already had its entries
pruned appropriately).
Pushed the fix.
Lee Bieber (kalebral-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Test failures - http://
also on freebsd, OSX and opensue
Lee Bieber (kalebral-deactivatedaccount) wrote : Posted in a previous version of this proposal | # |
Correction - not freebsd, that was an unrelated failure
Logfile for opensuse - http://
Logfile for OSX - http://
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
Ugh, the opensuse and osx failures are probably due to the boost::
I did fix the "build repeat tests twice" problem though. I'll leave this as work in progress until I can fully understand the other issue.. hopefully by Monday.
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
I was able to refactor out the [] overload of CacheMap which I believe was the culprit, causing me to return a reference to freed memory which subsequently would be overwritten.
Olaf van der Spek (olafvdspek) wrote : Posted in a previous version of this proposal | # |
On Mon, Mar 14, 2011 at 3:04 PM, Clint Byrum <email address hidden> wrote:
> Policy *policy= new (nothrow) Policy(
> if (policy == NULL or not policy->loadFile())
(nothrow) and policy == NULL are't needed (AFAIK).
> + UnorderedCheckM
Try to combine declaration and initialization of vars.
> + lock.unlock();
Not needed
> - CheckMap *new_cache;
Declare -> init
> - boost::
> - lock.lock();
> -
> - // Copy the current one
> - if (*check_cache)
> - {
> - new_cache= new CheckMap(
> - }
> - else
> - {
> - new_cache= new CheckMap();
> - }
? : operator is a better match here.
> - if (old_cache)
No need for the if.
> - {
> - delete old_cache;
> - }
Greetings,
Olaf
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal | # |
Olaf, are you reading the current merge proposal?
Most of the things you're suggesting I change are completely removed from the code.
To respond to the stuff that is still there:
nothrow and NULL check were the way I was told to avoid exception handling early on in drizzle's lifecycle when exceptions weren't used at all. I'll fix that in the next round of changes.
I've been explicit about calling lock.unlock() because I want to *see* the unlocks.
Olaf van der Spek (olafvdspek) wrote : Posted in a previous version of this proposal | # |
On Tue, Mar 15, 2011 at 7:23 AM, Clint Byrum <email address hidden> wrote:
> Olaf, are you reading the current merge proposal?
Oops. I replied to the lines with - instead of with + :p
--
Olaf
Olaf van der Spek (olafvdspek) wrote : | # |
> UnorderedCheckM
Why return an iterator? If an iterator isn't required, a pointer (to the value) would be better.
Brian Aker (brianaker) wrote : | # |
I am now looking at this.
Brian Aker (brianaker) wrote : | # |
I can't get this to merge :(
Clint Byrum (clint-fewbar) wrote : | # |
Merged with latest trunk now, so should merge into trunk cleanly for CI testing.
Brian Aker (brianaker) wrote : | # |
Now testing!
Preview Diff
1 | === modified file 'plugin/regex_policy/module.cc' |
2 | --- plugin/regex_policy/module.cc 2012-01-15 20:54:59 +0000 |
3 | +++ plugin/regex_policy/module.cc 2012-03-16 16:56:20 +0000 |
4 | @@ -23,6 +23,9 @@ |
5 | |
6 | #include <config.h> |
7 | |
8 | +#include <boost/unordered_set.hpp> |
9 | +#include <boost/thread/locks.hpp> |
10 | + |
11 | #include <drizzled/plugin/authorization.h> |
12 | #include <drizzled/module/option_map.h> |
13 | |
14 | @@ -38,10 +41,25 @@ |
15 | namespace regex_policy |
16 | { |
17 | |
18 | +uint64_t max_cache_buckets= DEFAULT_MAX_CACHE_BUCKETS; |
19 | +uint64_t max_lru_length= DEFAULT_MAX_LRU_LENGTH; |
20 | + |
21 | static int init(module::Context &context) |
22 | { |
23 | const module::option_map &vm= context.getOptions(); |
24 | |
25 | + max_cache_buckets= vm["max-cache-buckets"].as<uint64_t>(); |
26 | + if (max_cache_buckets < 1) |
27 | + { |
28 | + errmsg_printf(error::ERROR, _("max-cache-buckets is too low, must be greater than 0")); |
29 | + return 1; |
30 | + } |
31 | + max_lru_length= vm["max-lru-length"].as<uint64_t>(); |
32 | + if (max_lru_length < 1) |
33 | + { |
34 | + errmsg_printf(error::ERROR, _("max-lru-length is too low, must be greater than 0")); |
35 | + return 1; |
36 | + } |
37 | Policy *policy= new Policy(fs::path(vm["policy"].as<string>())); |
38 | if (not policy->loadFile()) |
39 | { |
40 | @@ -62,6 +80,12 @@ |
41 | context("policy", |
42 | po::value<string>()->default_value(DEFAULT_POLICY_FILE.string()), |
43 | N_("File to load for regex authorization policies")); |
44 | + context("max-cache-buckets", |
45 | + po::value<uint64_t>()->default_value(DEFAULT_MAX_CACHE_BUCKETS), |
46 | + N_("Maximum buckets for authorization cache")); |
47 | + context("max-lru-length", |
48 | + po::value<uint64_t>()->default_value(DEFAULT_MAX_LRU_LENGTH), |
49 | + N_("Maximum number of LRU entries to track at once")); |
50 | } |
51 | |
52 | bool Policy::loadFile() |
53 | @@ -169,14 +193,11 @@ |
54 | clearPolicyItemList(table_policies); |
55 | clearPolicyItemList(process_policies); |
56 | clearPolicyItemList(schema_policies); |
57 | - delete table_check_cache; |
58 | - delete process_check_cache; |
59 | - delete schema_check_cache; |
60 | } |
61 | |
62 | bool Policy::restrictObject(const drizzled::identifier::User &user_ctx, |
63 | const string &obj, const PolicyItemList &policies, |
64 | - CheckMap **check_cache) |
65 | + CheckMap &check_cache) |
66 | { |
67 | CheckItem c(user_ctx.username(), obj, check_cache); |
68 | if (!c.hasCachedResult()) |
69 | @@ -198,19 +219,19 @@ |
70 | bool Policy::restrictSchema(const drizzled::identifier::User &user_ctx, |
71 | const drizzled::identifier::Schema& schema) |
72 | { |
73 | - return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, &schema_check_cache); |
74 | + return restrictObject(user_ctx, schema.getSchemaName(), schema_policies, schema_check_cache); |
75 | } |
76 | |
77 | bool Policy::restrictProcess(const drizzled::identifier::User &user_ctx, |
78 | const drizzled::identifier::User &session_ctx) |
79 | { |
80 | - return restrictObject(user_ctx, session_ctx.username(), process_policies, &process_check_cache); |
81 | + return restrictObject(user_ctx, session_ctx.username(), process_policies, process_check_cache); |
82 | } |
83 | |
84 | bool Policy::restrictTable(const drizzled::identifier::User& user_ctx, |
85 | const drizzled::identifier::Table& table) |
86 | { |
87 | - return restrictObject(user_ctx, table.getTableName(), table_policies, &table_check_cache); |
88 | + return restrictObject(user_ctx, table.getTableName(), table_policies, table_check_cache); |
89 | } |
90 | |
91 | bool CheckItem::operator()(PolicyItem *p) |
92 | @@ -234,41 +255,104 @@ |
93 | return false; |
94 | } |
95 | |
96 | -CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap **check_cache_in) |
97 | +CheckItem::CheckItem(const std::string &user_in, const std::string &obj_in, CheckMap &check_cache_in) |
98 | : user(user_in), object(obj_in), has_cached_result(false), check_cache(check_cache_in) |
99 | { |
100 | - CheckMap::iterator check_val; |
101 | - std::stringstream keystream; |
102 | - keystream << user << "_" << object; |
103 | - key= keystream.str(); |
104 | - |
105 | - /* using RCU to only need to lock when updating the cache */ |
106 | - if ((*check_cache) && (check_val= (*check_cache)->find(key)) != (*check_cache)->end()) |
107 | - { |
108 | - setCachedResult(check_val->second); |
109 | + UnorderedCheckMap::iterator check_val; |
110 | + key= user + "_" + object; |
111 | + |
112 | + if ((check_val= check_cache.find(key)) != check_cache.end()) |
113 | + { |
114 | + /* It was in the cache, no need to do any more lookups */ |
115 | + cached_result= check_val->second; |
116 | + has_cached_result= true; |
117 | + } |
118 | +} |
119 | + |
120 | +UnorderedCheckMap::iterator CheckMap::find(std::string const &k) |
121 | +{ |
122 | + /* tack on to LRU list */ |
123 | + boost::mutex::scoped_lock lock(lru_mutex); |
124 | + lru.push_back(k); |
125 | + if (lru.size() > max_lru_length) |
126 | + { |
127 | + /* Fold all of the oldest entries into a single list at the front */ |
128 | + uint64_t size_halfway= lru.size() / 2; |
129 | + LruList::iterator halfway= lru.begin(); |
130 | + halfway += size_halfway; |
131 | + boost::unordered_set<std::string> uniqs; |
132 | + uniqs.insert(lru.begin(), halfway); |
133 | + |
134 | + /* If we can save space, drop the oldest half */ |
135 | + if (size_halfway < uniqs.size()) |
136 | + { |
137 | + lru.erase(lru.begin(), halfway); |
138 | + |
139 | + /* Re-add set elements to front */ |
140 | + lru.insert(lru.begin(), uniqs.begin(), uniqs.end()); |
141 | + } |
142 | + } |
143 | + lock.unlock(); |
144 | + boost::shared_lock<boost::shared_mutex> map_lock(map_mutex); |
145 | + return map.find(k); |
146 | +} |
147 | + |
148 | +void CheckMap::insert(std::string const &k, bool v) |
149 | +{ |
150 | + boost::unique_lock<boost::shared_mutex> map_lock(map_mutex); |
151 | + /* add our new hotness to the map */ |
152 | + map[k]=v; |
153 | + /* Now prune if necessary */ |
154 | + if (map.bucket_count() > max_cache_buckets) |
155 | + { |
156 | + /* Determine LRU key by running through the LRU list */ |
157 | + boost::unordered_set<std::string> found; |
158 | + |
159 | + /* Must unfortunately lock the LRU list while we traverse it */ |
160 | + boost::mutex::scoped_lock lock(lru_mutex); |
161 | + for (LruList::reverse_iterator x= lru.rbegin(); x < lru.rend(); ++x) |
162 | + { |
163 | + if (found.find(*x) == found.end()) |
164 | + { |
165 | + /* Newly found key */ |
166 | + if (found.size() >= max_cache_buckets) |
167 | + { |
168 | + /* Since found is already as big as the cache can be, anything else |
169 | + is LRU */ |
170 | + map.erase(*x); |
171 | + } |
172 | + else |
173 | + { |
174 | + found.insert(*x); |
175 | + } |
176 | + } |
177 | + } |
178 | + if (map.bucket_count() > max_cache_buckets) |
179 | + { |
180 | + /* Still too big. */ |
181 | + if (lru.size()) |
182 | + { |
183 | + /* Just delete the oldest item */ |
184 | + map.erase(*(lru.begin())); |
185 | + } |
186 | + else |
187 | + { |
188 | + /* Nothing to delete, warn */ |
189 | + errmsg_printf(error::WARN, |
190 | + _("Unable to reduce size of cache below max buckets (current buckets=%" PRIu64 ")"), |
191 | + static_cast<uint64_t>(map.bucket_count())); |
192 | + } |
193 | + } |
194 | + lru.clear(); |
195 | + lock.unlock(); |
196 | } |
197 | } |
198 | |
199 | void CheckItem::setCachedResult(bool result) |
200 | { |
201 | - // TODO: make the mutex per-cache |
202 | - boost::mutex::scoped_lock lock(check_cache_mutex, boost::defer_lock); |
203 | - lock.lock(); |
204 | - |
205 | - // Copy the current one |
206 | - CheckMap* new_cache= *check_cache ? new CheckMap(**check_cache) : new CheckMap; |
207 | - |
208 | - // Update it |
209 | - (*new_cache)[key]= result; |
210 | - // Replace old |
211 | - CheckMap* old_cache= *check_cache; |
212 | - *check_cache= new_cache; |
213 | - |
214 | - lock.unlock(); |
215 | + check_cache.insert(key, result); |
216 | has_cached_result= true; |
217 | cached_result= result; |
218 | - |
219 | - delete old_cache; |
220 | } |
221 | |
222 | } /* namespace regex_policy */ |
223 | |
224 | === modified file 'plugin/regex_policy/policy.h' |
225 | --- plugin/regex_policy/policy.h 2012-01-16 02:37:54 +0000 |
226 | +++ plugin/regex_policy/policy.h 2012-03-16 16:56:20 +0000 |
227 | @@ -29,6 +29,8 @@ |
228 | #include <boost/regex.hpp> |
229 | #include <boost/unordered_map.hpp> |
230 | #include <boost/thread/mutex.hpp> |
231 | +#include <boost/thread/shared_mutex.hpp> |
232 | +#include <boost/thread/locks.hpp> |
233 | |
234 | #include <drizzled/configmake.h> |
235 | #include <drizzled/plugin/authorization.h> |
236 | @@ -39,6 +41,9 @@ |
237 | |
238 | static const fs::path DEFAULT_POLICY_FILE= SYSCONFDIR "/drizzle.policy"; |
239 | |
240 | +static const uint64_t DEFAULT_MAX_LRU_LENGTH= 16384; |
241 | +static const uint64_t DEFAULT_MAX_CACHE_BUCKETS= 4096; |
242 | + |
243 | static const char *comment_regex = "^[[:space:]]*#.*$"; |
244 | static const char *empty_regex = "^[[:space:]]*$"; |
245 | static const char *table_match_regex = "^([^ ]+) table\\=([^ ]+) (ACCEPT|DENY)$"; |
246 | @@ -49,6 +54,7 @@ |
247 | static const int MATCH_REGEX_OBJECT_POS= 2; |
248 | static const int MATCH_REGEX_ACTION_POS= 3; |
249 | |
250 | + |
251 | typedef enum |
252 | { |
253 | POLICY_ACCEPT, |
254 | @@ -100,9 +106,23 @@ |
255 | }; |
256 | |
257 | typedef std::list<PolicyItem *> PolicyItemList; |
258 | -typedef boost::unordered_map<std::string, bool> CheckMap; |
259 | +typedef std::vector<std::string> LruList; |
260 | +typedef boost::unordered_map<std::string, bool> UnorderedCheckMap; |
261 | |
262 | -static boost::mutex check_cache_mutex; |
263 | +class CheckMap |
264 | +{ |
265 | + LruList lru; |
266 | + boost::mutex lru_mutex; |
267 | + boost::shared_mutex map_mutex; |
268 | + UnorderedCheckMap map; |
269 | +public: |
270 | + UnorderedCheckMap::iterator find(std::string const&k); |
271 | + UnorderedCheckMap::const_iterator end() const |
272 | + { |
273 | + return map.end(); |
274 | + } |
275 | + void insert(std::string const &k, bool v); |
276 | +}; |
277 | |
278 | class CheckItem |
279 | { |
280 | @@ -111,9 +131,9 @@ |
281 | std::string key; |
282 | bool has_cached_result; |
283 | bool cached_result; |
284 | - CheckMap **check_cache; |
285 | + CheckMap &check_cache; |
286 | public: |
287 | - CheckItem(const std::string &u, const std::string &obj, CheckMap **check_cache); |
288 | + CheckItem(const std::string &u, const std::string &obj, CheckMap &check_cache); |
289 | bool operator()(PolicyItem *p); |
290 | bool hasCachedResult() const |
291 | { |
292 | @@ -149,7 +169,7 @@ |
293 | public: |
294 | Policy(const fs::path &f_path) : |
295 | drizzled::plugin::Authorization("regex_policy"), policy_file(f_path), error(), |
296 | - table_check_cache(NULL), schema_check_cache(NULL), process_check_cache(NULL) |
297 | + table_check_cache(), schema_check_cache(), process_check_cache() |
298 | { } |
299 | |
300 | virtual bool restrictSchema(const drizzled::identifier::User &user_ctx, |
301 | @@ -167,15 +187,16 @@ |
302 | private: |
303 | bool restrictObject(const drizzled::identifier::User &user_ctx, |
304 | const std::string &obj, const PolicyItemList &policies, |
305 | - CheckMap **check_cache); |
306 | + CheckMap &check_cache); |
307 | fs::path policy_file; |
308 | + |
309 | std::stringstream error; |
310 | PolicyItemList table_policies; |
311 | PolicyItemList schema_policies; |
312 | PolicyItemList process_policies; |
313 | - CheckMap *table_check_cache; |
314 | - CheckMap *schema_check_cache; |
315 | - CheckMap *process_check_cache; |
316 | + CheckMap table_check_cache; |
317 | + CheckMap schema_check_cache; |
318 | + CheckMap process_check_cache; |
319 | }; |
320 | |
321 | } /* namespace regex_policy */ |
322 | |
323 | === added file 'plugin/regex_policy/tests/r/cache_overflow.result' |
324 | --- plugin/regex_policy/tests/r/cache_overflow.result 1970-01-01 00:00:00 +0000 |
325 | +++ plugin/regex_policy/tests/r/cache_overflow.result 2012-03-16 16:56:20 +0000 |
326 | @@ -0,0 +1,73 @@ |
327 | +create schema user0; |
328 | +create schema user1; |
329 | +create schema user2; |
330 | +create schema user3; |
331 | +create schema user4; |
332 | +create schema user5; |
333 | +create schema user6; |
334 | +create schema user7; |
335 | +SELECT SCHEMA_NAME FROM DATA_DICTIONARY.SCHEMAS ORDER BY SCHEMA_NAME; |
336 | +SCHEMA_NAME |
337 | +DATA_DICTIONARY |
338 | +INFORMATION_SCHEMA |
339 | +mysql |
340 | +test |
341 | +user0 |
342 | +user1 |
343 | +user2 |
344 | +user3 |
345 | +user4 |
346 | +user5 |
347 | +user6 |
348 | +user7 |
349 | +use user0; |
350 | +create table t1 (id int); |
351 | +insert into t1 values(1); |
352 | +create table user1.t1 as select * from user0.t1; |
353 | +create table user2.t1 as select * from user0.t1; |
354 | +create table user3.t1 as select * from user0.t1; |
355 | +create table user4.t1 as select * from user0.t1; |
356 | +create table user5.t1 as select * from user0.t1; |
357 | +create table user6.t1 as select * from user0.t1; |
358 | +create table user7.t1 as select * from user0.t1; |
359 | +SELECT * from user1.dont_exist0; |
360 | +ERROR 42S02: Unknown table 'user1.dont_exist0' |
361 | +SELECT * from user1.dont_exist1; |
362 | +ERROR 42S02: Unknown table 'user1.dont_exist1' |
363 | +SELECT * from user1.dont_exist2; |
364 | +ERROR 42S02: Unknown table 'user1.dont_exist2' |
365 | +SELECT * from user1.dont_exist3; |
366 | +ERROR 42S02: Unknown table 'user1.dont_exist3' |
367 | +SELECT * from user1.dont_exist4; |
368 | +ERROR 42S02: Unknown table 'user1.dont_exist4' |
369 | +SELECT * from user1.dont_exist5; |
370 | +ERROR 42S02: Unknown table 'user1.dont_exist5' |
371 | +SELECT * from user1.dont_exist6; |
372 | +ERROR 42S02: Unknown table 'user1.dont_exist6' |
373 | +SELECT * from user1.dont_exist7; |
374 | +ERROR 42S02: Unknown table 'user1.dont_exist7' |
375 | +SELECT * from user1.t1; |
376 | +id |
377 | +1 |
378 | +SELECT * from user0.t1; |
379 | +ERROR 42000: Access denied for user 'user1' to schema 'user0' |
380 | +SELECT * from user2.t1; |
381 | +ERROR 42000: Access denied for user 'user1' to schema 'user2' |
382 | +SELECT * from user3.t1; |
383 | +ERROR 42000: Access denied for user 'user1' to schema 'user3' |
384 | +SELECT * from user4.t1; |
385 | +ERROR 42000: Access denied for user 'user1' to schema 'user4' |
386 | +SELECT * from user5.t1; |
387 | +ERROR 42000: Access denied for user 'user1' to schema 'user5' |
388 | +SELECT * from user6.t1; |
389 | +ERROR 42000: Access denied for user 'user1' to schema 'user6' |
390 | +SELECT * from user7.t1; |
391 | +ERROR 42000: Access denied for user 'user1' to schema 'user7' |
392 | +drop schema user0; |
393 | +drop schema user1; |
394 | +drop schema user2; |
395 | +drop schema user3; |
396 | +drop schema user4; |
397 | +drop schema user5; |
398 | +drop schema user6; |
399 | +drop schema user7; |
400 | |
401 | === added file 'plugin/regex_policy/tests/t/cache_overflow-master.opt' |
402 | --- plugin/regex_policy/tests/t/cache_overflow-master.opt 1970-01-01 00:00:00 +0000 |
403 | +++ plugin/regex_policy/tests/t/cache_overflow-master.opt 2012-03-16 16:56:20 +0000 |
404 | @@ -0,0 +1,1 @@ |
405 | +--plugin-add=regex_policy --regex-policy.policy=$TOP_SRCDIR/plugin/regex_policy/tests/t/basic.policy --verbose=INSPECT --regex-policy.max-cache-buckets=5 --regex-policy.max-lru-length=7 |
406 | |
407 | === added file 'plugin/regex_policy/tests/t/cache_overflow.test' |
408 | --- plugin/regex_policy/tests/t/cache_overflow.test 1970-01-01 00:00:00 +0000 |
409 | +++ plugin/regex_policy/tests/t/cache_overflow.test 2012-03-16 16:56:20 +0000 |
410 | @@ -0,0 +1,70 @@ |
411 | +# Check for error if no parameter provided |
412 | +create schema user0; |
413 | +create schema user1; |
414 | +create schema user2; |
415 | +create schema user3; |
416 | +create schema user4; |
417 | +create schema user5; |
418 | +create schema user6; |
419 | +create schema user7; |
420 | +SELECT SCHEMA_NAME FROM DATA_DICTIONARY.SCHEMAS ORDER BY SCHEMA_NAME; |
421 | + |
422 | +# Set up a table to be able to test not being able to kill other people |
423 | +use user0; |
424 | +create table t1 (id int); |
425 | +insert into t1 values(1); |
426 | +create table user1.t1 as select * from user0.t1; |
427 | +create table user2.t1 as select * from user0.t1; |
428 | +create table user3.t1 as select * from user0.t1; |
429 | +create table user4.t1 as select * from user0.t1; |
430 | +create table user5.t1 as select * from user0.t1; |
431 | +create table user6.t1 as select * from user0.t1; |
432 | +create table user7.t1 as select * from user0.t1; |
433 | + |
434 | +connect (should_succeed,localhost,user1,,user1,,); |
435 | +connection should_succeed; |
436 | +# Try selecting from 8 tables that don't exist |
437 | +--error ER_TABLE_UNKNOWN |
438 | +SELECT * from user1.dont_exist0; |
439 | +--error ER_TABLE_UNKNOWN |
440 | +SELECT * from user1.dont_exist1; |
441 | +--error ER_TABLE_UNKNOWN |
442 | +SELECT * from user1.dont_exist2; |
443 | +--error ER_TABLE_UNKNOWN |
444 | +SELECT * from user1.dont_exist3; |
445 | +--error ER_TABLE_UNKNOWN |
446 | +SELECT * from user1.dont_exist4; |
447 | +--error ER_TABLE_UNKNOWN |
448 | +SELECT * from user1.dont_exist5; |
449 | +--error ER_TABLE_UNKNOWN |
450 | +SELECT * from user1.dont_exist6; |
451 | +--error ER_TABLE_UNKNOWN |
452 | +SELECT * from user1.dont_exist7; |
453 | + |
454 | +# Try accessing 8 different existing schemas/tables |
455 | +SELECT * from user1.t1; |
456 | +--error ER_DBACCESS_DENIED_ERROR |
457 | +SELECT * from user0.t1; |
458 | +--error ER_DBACCESS_DENIED_ERROR |
459 | +SELECT * from user2.t1; |
460 | +--error ER_DBACCESS_DENIED_ERROR |
461 | +SELECT * from user3.t1; |
462 | +--error ER_DBACCESS_DENIED_ERROR |
463 | +SELECT * from user4.t1; |
464 | +--error ER_DBACCESS_DENIED_ERROR |
465 | +SELECT * from user5.t1; |
466 | +--error ER_DBACCESS_DENIED_ERROR |
467 | +SELECT * from user6.t1; |
468 | +--error ER_DBACCESS_DENIED_ERROR |
469 | +SELECT * from user7.t1; |
470 | + |
471 | +connection default; |
472 | +drop schema user0; |
473 | +drop schema user1; |
474 | +drop schema user2; |
475 | +drop schema user3; |
476 | +drop schema user4; |
477 | +drop schema user5; |
478 | +drop schema user6; |
479 | +drop schema user7; |
480 | +disconnect should_succeed; |
AFAIK there's a format specifier for size_t.