File: sql_thd_api.cc

package info (click to toggle)
mysql-8.0 8.0.43-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,273,924 kB
  • sloc: cpp: 4,684,605; ansic: 412,450; pascal: 108,398; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; sh: 24,181; python: 21,816; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,076; makefile: 2,194; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (717 lines) | stat: -rw-r--r-- 21,352 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
/* Copyright (c) 2015, 2025, Oracle and/or its affiliates.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License, version 2.0,
   as published by the Free Software Foundation.

   This program is designed to work with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have either included with
   the program or referenced in the documentation.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License, version 2.0, for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */

#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <atomic>

#include "lex_string.h"
#include "m_ctype.h"
#include "my_compiler.h"
#include "my_dbug.h"
#include "my_io.h"
#include "my_macros.h"
#include "my_sqlcommand.h"
#include "my_thread.h"
#include "my_thread_local.h"
#include "mysql/components/services/bits/psi_stage_bits.h"
#include "mysql/components/services/bits/psi_thread_bits.h"
#include "mysql/plugin.h"
#include "mysql/psi/mysql_mutex.h"
#include "mysql/service_thd_engine_lock.h"
#include "mysql_com.h"
#include "sql/auth/auth_acls.h"
#include "sql/auth/sql_security_ctx.h"
#include "sql/conn_handler/connection_handler_manager.h"
#include "sql/current_thd.h"  // current_thd
#include "sql/handler.h"
#include "sql/mysqld.h"  // key_thread_one_connection
#include "sql/protocol_classic.h"
#include "sql/query_options.h"
#include "sql/resourcegroups/platform/thread_attrs_api.h"  // num_vcpus
#include "sql/rpl_replica_commit_order_manager.h"  // check_and_report_deadlock
#include "sql/rpl_rli.h"                           // is_mts_worker
#include "sql/sql_alter.h"
#include "sql/sql_callback.h"  // MYSQL_CALLBACK
#include "sql/sql_class.h"     // THD
#include "sql/sql_error.h"
#include "sql/sql_lex.h"
#include "sql/sql_plugin.h"  // plugin_unlock
#include "sql/sql_plugin_ref.h"
#include "sql/sql_thd_internal_api.h"
#include "sql/strfunc.h"
#include "sql/system_variables.h"
#include "sql/transaction_info.h"
#include "sql/xa.h"
#include "sql_string.h"
#include "violite.h"

struct MYSQL_LEX_STRING;

using std::min;

//////////////////////////////////////////////////////////
//
//  Definitions of functions declared in thread_pool_priv.h
//
//////////////////////////////////////////////////////////

/**
  Get reference to scheduler data object

  @param thd            THD object

  @retval               Scheduler data object on THD
*/

void *thd_get_scheduler_data(THD *thd) { return thd->scheduler.data; }

/**
  Set reference to Scheduler data object for THD object

  @param thd            THD object
  @param data           Scheduler data object to set on THD
*/

void thd_set_scheduler_data(THD *thd, void *data) {
  thd->scheduler.data = data;
}

/**
  Get reference to Performance Schema object for THD object

  @param thd            THD object

  @retval               Performance schema object for thread on THD
*/

PSI_thread *thd_get_psi(THD *thd) { return thd->get_psi(); }

/**
  Get net_wait_timeout for THD object

  @param thd            THD object

  @retval               net_wait_timeout value for thread on THD
*/

ulong thd_get_net_wait_timeout(THD *thd) {
  return thd->variables.net_wait_timeout;
}

/**
  Set reference to Performance Schema object for THD object

  @param thd            THD object
  @param psi            Performance schema object for thread
*/

void thd_set_psi(THD *thd, PSI_thread *psi) { thd->set_psi(psi); }

/**
  Set the state on connection to killed

  @param thd               THD object
*/

void thd_set_killed(THD *thd) {
  /*
    TODO: This method just sets the state of the THD::killed member. Now used
          for the idle threads. To awake and set killed status for active
          threads, THD::awake() should be used as part of this method or in a
          new API.
          Setting KILL state for a thread in a kill immune mode is handled
          as part of THD::awake(). Direct KILL state set for active thread
          breaks it.
  */
  thd->killed = THD::KILL_CONNECTION;
}

/**
  Clear errors from the previous THD

  @param thd              THD object
*/

void thd_clear_errors(THD *thd [[maybe_unused]]) { set_my_errno(0); }

/**
  Close the socket used by this connection

  @param thd                THD object
  @note Expects lock on thd->LOCK_thd_data.
*/

void thd_close_connection(THD *thd) {
  mysql_mutex_assert_owner(&thd->LOCK_thd_data);
  thd->shutdown_active_vio();
}

/**
  Get current THD object from thread local data

  @retval     The THD object for the thread, NULL if not connection thread
*/

THD *thd_get_current_thd() { return current_thd; }

/**
  Reset thread globals associated.

  @param thd     THD object
*/

void reset_thread_globals(THD *thd) {
  thd->restore_globals();
  thd->set_is_killable(false);
}

/**
  Lock data that needs protection in THD object

  @param thd                   THD object
*/

void thd_lock_data(THD *thd) { mysql_mutex_lock(&thd->LOCK_thd_data); }

/**
  Unlock data that needs protection in THD object

  @param thd                   THD object
*/

void thd_unlock_data(THD *thd) { mysql_mutex_unlock(&thd->LOCK_thd_data); }

/**
  Support method to check if connection has already started transaction

  @param thd Current thread

  @retval               true if connection already started transaction
*/

bool thd_is_transaction_active(THD *thd) {
  return thd->get_transaction()->is_active(Transaction_ctx::SESSION);
}

/**
  Predicate for determining if connection is in active multi-statement
  transaction.
 */
bool thd_in_active_multi_stmt_transaction(const THD *thd) {
  return thd->in_active_multi_stmt_transaction();
}

/**
  Check if there is buffered data on the socket representing the connection

  @param thd                  THD object
*/

int thd_connection_has_data(THD *thd) {
  Vio *vio = thd->get_protocol_classic()->get_vio();
  return vio->has_data(vio);
}

/**
  Get reading/writing on socket from THD object
  @param thd                       THD object

  @retval               net.reading_or_writing value for thread on THD.
*/

uint thd_get_net_read_write(THD *thd) {
  return thd->get_protocol_classic()->get_rw_status();
}

/**
  Set reading/writing on socket, used by SHOW PROCESSLIST

  @param thd                       THD object
  @param val                       Value to set it to (0 or 1)
*/

void thd_set_net_read_write(THD *thd, uint val) {
  thd->get_protocol_classic()->get_net()->reading_or_writing = val;
  thd->store_cached_properties(THD::cached_properties::RW_STATUS);
}

/**
  Mark the THD as not killable as it is not currently used by a thread.

  @param thd             THD object
*/

void thd_set_not_killable(THD *thd) { thd->set_is_killable(false); }

/**
  Get socket file descriptor for this connection

  @param thd            THD object

  @retval               Socket of the connection
*/

my_socket thd_get_fd(THD *thd) {
  return thd->get_protocol_classic()->get_socket();
}

/**
  Set thread specific environment required for thd cleanup in thread pool.

  @param thd            THD object
*/

void thd_store_globals(THD *thd) { thd->store_globals(); }

/**
  Get thread attributes for connection threads

  @retval      Reference to thread attribute for connection threads
*/

my_thread_attr_t *get_connection_attrib() { return &connection_attrib; }

/**
  Get max number of connections

  @retval         Max number of connections for MySQL Server
*/

ulong get_max_connections() { return max_connections; }

//////////////////////////////////////////////////////////
//
//  Definitions of functions declared in plugin.h
//
//////////////////////////////////////////////////////////

void thd_binlog_pos(const MYSQL_THD thd, const char **file_var,
                    unsigned long long *pos_var) {
  thd->get_trans_pos(file_var, pos_var);
}

int mysql_tmpfile(const char *prefix) {
  return mysql_tmpfile_path(mysql_tmpdir, prefix);
}

int thd_in_lock_tables(const MYSQL_THD thd) { return thd->in_lock_tables; }

int thd_tablespace_op(const MYSQL_THD thd) {
  /*
    The Alter_info is reset only at the beginning of an ALTER
    statement, so this function must check both the SQL command
    code and the Alter_info::flags.
  */
  int ret = 0;

  if (thd->lex->sql_command == SQLCOM_ALTER_TABLE) {
    if (thd->lex->alter_info->flags & Alter_info::ALTER_DISCARD_TABLESPACE) {
      ret = Alter_info::ALTER_DISCARD_TABLESPACE;
    }
    if (thd->lex->alter_info->flags & Alter_info::ALTER_IMPORT_TABLESPACE) {
      ret = Alter_info::ALTER_IMPORT_TABLESPACE;
    }
  }

  return (ret);
}

static void set_thd_stage_info(MYSQL_THD thd, const PSI_stage_info *new_stage,
                               PSI_stage_info *old_stage,
                               const char *calling_func,
                               const char *calling_file,
                               const unsigned int calling_line) {
  if (thd == nullptr) thd = current_thd;

  thd->enter_stage(new_stage, old_stage, calling_func, calling_file,
                   calling_line);
}

extern "C" const char *set_thd_proc_info(MYSQL_THD thd_arg, const char *info,
                                         const char *calling_function,
                                         const char *calling_file,
                                         const unsigned int calling_line) {
  PSI_stage_info old_stage;
  PSI_stage_info new_stage;

  old_stage.m_key = 0;
  old_stage.m_name = info;

  set_thd_stage_info(thd_arg, &old_stage, &new_stage, calling_function,
                     calling_file, calling_line);

  return new_stage.m_name;
}

void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton) {
  return &(const_cast<THD *>(thd))->get_ha_data(hton->slot)->ha_ptr;
}

void thd_storage_lock_wait(MYSQL_THD thd, long long value) {
  thd->inc_lock_usec(value);
}

/**
  Provide a handler data getter to simplify coding
*/
void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton) {
  return *thd_ha_data(thd, hton);
}

/**
  Provide a handler data setter to simplify coding
  @see thd_set_ha_data() definition in plugin.h
*/
void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton,
                     const void *ha_data) {
  plugin_ref *lock = &thd->get_ha_data(hton->slot)->lock;
  if (ha_data && !*lock)
    *lock = ha_lock_engine(nullptr, hton);
  else if (!ha_data && *lock) {
    plugin_unlock(nullptr, *lock);
    *lock = nullptr;
  }
  *thd_ha_data(thd, hton) = const_cast<void *>(ha_data);
}

long long thd_test_options(const MYSQL_THD thd, long long test_options) {
  return thd->variables.option_bits & test_options;
}

int thd_sql_command(const MYSQL_THD thd) { return (int)thd->lex->sql_command; }

int thd_tx_isolation(const MYSQL_THD thd) { return (int)thd->tx_isolation; }

int thd_tx_is_read_only(const MYSQL_THD thd) { return (int)thd->tx_read_only; }

int thd_tx_priority(const MYSQL_THD thd) {
  return (thd->thd_tx_priority != 0 ? thd->thd_tx_priority : thd->tx_priority);
}

MYSQL_THD thd_tx_arbitrate(MYSQL_THD requestor, MYSQL_THD holder) {
  /* Should be different sessions. */
  assert(holder != requestor);

  return (thd_tx_priority(requestor) == thd_tx_priority(holder)
              ? requestor
              : ((thd_tx_priority(requestor) > thd_tx_priority(holder))
                     ? holder
                     : requestor));
}

int thd_tx_is_dd_trx(const MYSQL_THD thd) {
  return (int)thd->is_attachable_ro_transaction_active();
}

void thd_inc_row_count(MYSQL_THD thd) {
  thd->get_stmt_da()->inc_current_row_for_condition();
}

/**
  Returns the size of the beginning part of a (multibyte) string,
  which can fit in max_size bytes.

  @param[in] cs charset_info
  @param[in] start pointer to the string
  @param[in] original_size the length of the string (in bytes)
  @param[in] max_size the size of the buffer which needs to hold the string
  @return  the maximum length of a prefix of the string, that can be stored
*/
static size_t truncated_str_length(const CHARSET_INFO *cs, const char *start,
                                   size_t original_size, size_t max_size) {
  if (max_size >= original_size) return original_size;

  uint next_char_len;
  auto next_char = start;
  auto end = start + original_size;

  while ((next_char_len = my_mbcharlen_ptr(cs, next_char, end)) > 0 &&
         (size_t)(next_char + next_char_len - start) <= max_size) {
    next_char += next_char_len;
    assert(next_char < end);
    // *next_char is always a valid expression, since max_size < original_size
  }
  return next_char - start;
}

/**
  Dumps a text description of a thread, its security context
  (user, host) and the current query.

  @param thd thread context
  @param buffer pointer to preferred result buffer
  @param length length of buffer
  @param max_query_len how many chars of query to copy (0 for all)

  @return Pointer to string
*/

char *thd_security_context(MYSQL_THD thd, char *buffer, size_t length,
                           size_t max_query_len) {
  String str(buffer, length, &my_charset_latin1);
  Security_context *sctx = &thd->m_main_security_ctx;
  char header[256];
  size_t len;
  /*
    The pointers thd->query and thd->proc_info might change since they are
    being modified concurrently. This is acceptable for proc_info since its
    values doesn't have to very accurate and the memory it points to is static,
    but we need to attempt a snapshot on the pointer values to avoid using NULL
    values. The pointer to thd->query however, doesn't point to static memory
    and has to be protected by LOCK_thd_query or risk pointing to
    uninitialized memory.
  */
  const char *proc_info = thd->proc_info();

  len = snprintf(header, sizeof(header),
                 "MySQL thread id %u, OS thread handle %lu, query id %lu",
                 thd->thread_id(), (ulong)thd->real_id, (ulong)thd->query_id);
  str.length(0);
  str.append(header, len);

  if (sctx->host().length) {
    str.append(' ');
    str.append(sctx->host().str);
  }

  if (sctx->ip().length) {
    str.append(' ');
    str.append(sctx->ip().str);
  }

  if (sctx->user().str) {
    str.append(' ');
    str.append(sctx->user().str);
  }

  if (proc_info) {
    str.append(' ');
    str.append(proc_info);
  }

  mysql_mutex_lock(&thd->LOCK_thd_query);

  if (thd->query().str) {
    if (max_query_len < 1)
      len = thd->query().length;
    else
      len = min(thd->query().length, max_query_len);
    str.append('\n');
    str.append(thd->query().str,
               truncated_str_length(thd->charset(), thd->query().str,
                                    thd->query().length, len));
  }

  mysql_mutex_unlock(&thd->LOCK_thd_query);

  if (str.c_ptr_safe() == buffer) return buffer;

  /*
    We have to copy the new string to the destination buffer because the string
    was reallocated to a larger buffer to be able to fit.
  */
  assert(buffer != nullptr);
  length = truncated_str_length(thd->charset(), str.c_ptr_quick(), str.length(),
                                length - 1);
  memcpy(buffer, str.c_ptr_quick(), length);
  /* Make sure that the new string is null terminated */
  buffer[length] = '\0';
  return buffer;
}

void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid) {
  *xid = *pointer_cast<const MYSQL_XID *>(
      thd->get_transaction()->xid_state()->get_xid());
}

int thd_killed(const void *v_thd) {
  const THD *thd = static_cast<const THD *>(v_thd);
  if (thd == nullptr) thd = current_thd;
  if (thd == nullptr) return 0;
  return thd->killed;
}

/**
  Set the killed status of the current statement.

  @param thd  user thread connection handle
*/

void thd_set_kill_status(const MYSQL_THD thd) { thd->send_kill_message(); }

unsigned long thd_get_thread_id(const MYSQL_THD thd) {
  return ((unsigned long)thd->thread_id());
}

/**
  Check if batching is allowed for the thread
  @param thd  user thread
  @retval 1 batching allowed
  @retval 0 batching not allowed
*/

int thd_allow_batch(MYSQL_THD thd) {
  if ((thd->variables.option_bits & OPTION_ALLOW_BATCH) ||
      (thd->slave_thread && opt_replica_allow_batching))
    return 1;
  return 0;
}

void thd_mark_transaction_to_rollback(MYSQL_THD thd, int all) {
  DBUG_TRACE;
  assert(thd);
  /*
    The parameter "all" has type int since the function is defined
    in plugin.h. The corresponding parameter in the call below has
    type bool. The comment in plugin.h states that "all != 0"
    means to rollback the main transaction. Thus, check this
    specifically.
  */
  thd->mark_transaction_to_rollback((all != 0));
}

//////////////////////////////////////////////////////////
//
//  Definitions of functions declared in service_thd_alloc.h
//
//////////////////////////////////////////////////////////

void *thd_alloc(MYSQL_THD thd, size_t size) { return thd->alloc(size); }

void *thd_calloc(MYSQL_THD thd, size_t size) { return thd->mem_calloc(size); }

char *thd_strdup(MYSQL_THD thd, const char *str) {
  return thd->mem_strdup(str);
}

char *thd_strmake(MYSQL_THD thd, const char *str, size_t size) {
  return thd->strmake(str, size);
}

MYSQL_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_LEX_STRING *lex_str,
                                      const char *str, size_t size,
                                      int allocate_lex_string) {
  if (allocate_lex_string != 0)
    return make_lex_string_root(thd->mem_root, str, size);
  if (lex_string_strmake(thd->mem_root, lex_str, str, size)) return nullptr;
  return lex_str;
}

void *thd_memdup(MYSQL_THD thd, const void *str, size_t size) {
  return thd->memdup(str, size);
}

//////////////////////////////////////////////////////////
//
//  Definitions of functions declared in service_thd_wait.h
//
//////////////////////////////////////////////////////////

/**
  Interface for MySQL Server, plugins and storage engines to report
  when they are going to sleep/stall.

  This is currently only implemented by by the threadpool and used to have
  better knowledge of which threads that currently are actively running on CPUs.
  When not running with TP this makes a call, possibly through a service,
  to an empty function.

  thd_wait_end MUST be called immediately after waking up again.

  More info can be found in the TP documentation.

  @param thd Calling thread context. If nullptr is passed, current_thd is used.
  @param wait_type An enum value from the enum thd_wait_type (defined
                   in include/mysql/service_thd_wait.h) but passed as int
                   to preserve compatibility with exported service api.
*/
void thd_wait_begin(MYSQL_THD thd, int wait_type) {
  MYSQL_CALLBACK(Connection_handler_manager::event_functions, thd_wait_begin,
                 (thd, wait_type));
}

/**
  Interface for MySQL Server, plugins and storage engines to report
  when they waking up from a sleep/stall.

  This is currently only implemented by by the threadpool and used to have
  better knowledge of which threads that currently are actively running on CPUs.
  When not running with TP this makes a call, possibly through a service,
  to an empty function.

  More info can be found in the TP documentation.

  @param thd Calling thread context. If nullptr is passed, current_thd is used.
*/
void thd_wait_end(MYSQL_THD thd) {
  MYSQL_CALLBACK(Connection_handler_manager::event_functions, thd_wait_end,
                 (thd));
}

//////////////////////////////////////////////////////////
//
//  Definitions of functions declared in service_thd_engine_lock.h
//
//////////////////////////////////////////////////////////

void thd_report_row_lock_wait(THD *self, THD *wait_for) {
  DBUG_TRACE;
  thd_report_lock_wait(self, wait_for, true);
}

void thd_report_lock_wait(THD *self, THD *wait_for,
                          bool /* may_survive_prepare*/) {
  DBUG_TRACE;
  CONDITIONAL_SYNC_POINT("report_lock_collision");

  if (self != nullptr && wait_for != nullptr && is_mts_worker(self) &&
      is_mts_worker(wait_for))
    Commit_order_manager::check_and_report_deadlock(self, wait_for);
}

/**
  Interface for cleaning the openssl per thread error queue.
*/

void remove_ssl_err_thread_state() {
#if !defined(HAVE_OPENSSL11)
  ERR_remove_thread_state(nullptr);
#endif
}

unsigned int thd_get_num_vcpus() {
  return resourcegroups::platform::num_vcpus();
}

bool thd_check_connection_admin_privilege(MYSQL_THD thd) {
  Security_context *sctx = thd->security_context();
  return (!(sctx->check_access(SUPER_ACL) ||
            sctx->has_global_grant(STRING_WITH_LEN("CONNECTION_ADMIN")).first));
}

unsigned int thd_get_current_thd_terminology_use_previous() {
  if (!current_thd) return 0;
  return current_thd->variables.terminology_use_previous;
}