/* Copyright (c) 2008, 2023, 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 also distributed 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 included with MySQL .
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 ,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
#include <my_global.h>
#include "table_session_connect.h"
#include "field.h"
table_session_connect::table_session_connect(const PFS_engine_table_share *share)
: cursor_by_thread_connect_attr(share)
{
if (session_connect_attrs_size_per_thread > 0 )
{
m_copy_session_connect_attrs= (char *) my_malloc(PSI_INSTRUMENT_ME,
session_connect_attrs_size_per_thread,
MYF(0 ));
}
else
{
m_copy_session_connect_attrs= NULL;
}
m_copy_session_connect_attrs_length= 0 ;
}
table_session_connect::~table_session_connect()
{
my_free(m_copy_session_connect_attrs);
}
/**
Take a length encoded string
@ arg ptr inout the input string array
@ arg dest where to store the result
@ arg dest_size max size of @ c dest
@ arg copied_len the actual length of the data copied
@ arg start_ptr pointer to the start of input
@ arg input_length the length of the incoming data
@ arg copy_data copy the data or just skip the input
@ arg from_cs character set in which @ c ptr is encoded
@ arg nchars_max maximum number of characters to read
@ return status
@ retval true parsing failed
@ retval false parsing succeeded
*/
bool parse_length_encoded_string(const char **ptr,
char *dest, uint dest_size,
uint *copied_len,
const char *start_ptr, uint input_length,
bool copy_data,
const CHARSET_INFO *from_cs,
uint nchars_max)
{
ulong copy_length, data_length;
String_copier copier;
copy_length= data_length= net_field_length((uchar **) ptr);
/* we don't tolerate NULL as a length */
if (data_length == NULL_LENGTH)
return true ;
if (*ptr - start_ptr + data_length > input_length)
return true ;
copy_length= copier.well_formed_copy(&my_charset_utf8mb3_bin, dest, dest_size,
from_cs, *ptr, data_length, nchars_max);
*copied_len= copy_length;
(*ptr)+= data_length;
return false ;
}
/**
Take the nth attribute name / value pair
Parse the attributes blob form the beginning , skipping the attributes
whose number is lower than the one we seek .
When we reach the attribute at an index we ' re looking for the values
are copied to the output parameters .
If parsing fails or no more attributes are found the function stops
and returns an error code .
@ arg connect_attrs pointer to the connect attributes blob
@ arg connect_attrs_length length of @ c connect_attrs
@ arg connect_attrs_cs character set used to encode @ c connect_attrs
@ arg ordinal index of the attribute we need
@ arg attr_name [ out ] buffer to receive the attribute name
@ arg max_attr_name max size of @ c attr_name in bytes
@ arg attr_name_length [ out ] number of bytes written in @ attr_name
@ arg attr_value [ out ] buffer to receive the attribute name
@ arg max_attr_value max size of @ c attr_value in bytes
@ arg attr_value_length [ out ] number of bytes written in @ attr_value
@ return status
@ retval true requested attribute pair is found and copied
@ retval false error . Either because of parsing or too few attributes .
*/
bool read_nth_attr(const char *connect_attrs,
uint connect_attrs_length,
const CHARSET_INFO *connect_attrs_cs,
uint ordinal,
char *attr_name, uint max_attr_name,
uint *attr_name_length,
char *attr_value, uint max_attr_value,
uint *attr_value_length)
{
uint idx;
const char *ptr;
for (ptr= connect_attrs, idx= 0 ;
(uint)(ptr - connect_attrs) < connect_attrs_length && idx <= ordinal;
idx++)
{
uint copy_length;
/* do the copying only if we absolutely have to */
bool fill_in_attr_name= idx == ordinal;
bool fill_in_attr_value= idx == ordinal;
/* read the key */
if (parse_length_encoded_string(&ptr,
attr_name, max_attr_name, ©_length,
connect_attrs,
connect_attrs_length,
fill_in_attr_name,
connect_attrs_cs, 32 ) ||
!copy_length
)
return false ;
if (idx == ordinal)
*attr_name_length= copy_length;
/* read the value */
if (parse_length_encoded_string(&ptr,
attr_value, max_attr_value, ©_length,
connect_attrs,
connect_attrs_length,
fill_in_attr_value,
connect_attrs_cs, 1024 ))
return false ;
if (idx == ordinal)
*attr_value_length= copy_length;
if (idx == ordinal)
return true ;
}
return false ;
}
void table_session_connect::make_row(PFS_thread *pfs, uint ordinal)
{
pfs_optimistic_state lock;
pfs_optimistic_state session_lock;
PFS_thread_class *safe_class;
const CHARSET_INFO *cs;
m_row_exists= false ;
/* Protect this reader against thread termination */
pfs->m_lock.begin_optimistic_lock(&lock);
/* Protect this reader against writing on session attributes */
pfs->m_session_lock.begin_optimistic_lock(&session_lock);
safe_class= sanitize_thread_class(pfs->m_class);
if (unlikely(safe_class == NULL))
return ;
/* Filtering threads must be done under the protection of the optimistic lock. */
if (! thread_fits(pfs))
return ;
/* Make a safe copy of the session attributes */
if (m_copy_session_connect_attrs == NULL)
return ;
m_copy_session_connect_attrs_length= pfs->m_session_connect_attrs_length;
if (m_copy_session_connect_attrs_length > session_connect_attrs_size_per_thread)
return ;
memcpy(m_copy_session_connect_attrs,
pfs->m_session_connect_attrs,
m_copy_session_connect_attrs_length);
cs= get_charset(pfs->m_session_connect_attrs_cs_number, MYF(0 ));
if (cs == NULL)
return ;
if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
return ;
if (! pfs->m_lock.end_optimistic_lock(& lock))
return ;
/*
Now we have a safe copy of the data ,
that will not change while parsing it
*/
/* populate the row */
if (read_nth_attr(m_copy_session_connect_attrs,
m_copy_session_connect_attrs_length,
cs,
ordinal,
m_row.m_attr_name, (uint) sizeof (m_row.m_attr_name),
&m_row.m_attr_name_length,
m_row.m_attr_value, (uint) sizeof (m_row.m_attr_value),
&m_row.m_attr_value_length))
{
/* we don't expect internal threads to have connection attributes */
if (pfs->m_processlist_id == 0 )
return ;
m_row.m_ordinal_position= ordinal;
m_row.m_process_id= pfs->m_processlist_id;
m_row_exists= true ;
}
}
int table_session_connect::read_row_values(TABLE *table,
unsigned char *buf,
Field **fields,
bool read_all)
{
Field *f;
if (unlikely(!m_row_exists))
return HA_ERR_RECORD_DELETED;
/* Set the null bits */
assert(table->s->null_bytes == 1 );
buf[0 ]= 0 ;
for (; (f= *fields) ; fields++)
{
if (read_all || bitmap_is_set(table->read_set, f->field_index))
{
switch (f->field_index)
{
case FO_PROCESS_ID:
if (m_row.m_process_id != 0 )
set_field_ulong(f, m_row.m_process_id);
else
f->set_null();
break ;
case FO_ATTR_NAME:
set_field_varchar_utf8(f, m_row.m_attr_name,
m_row.m_attr_name_length);
break ;
case FO_ATTR_VALUE:
if (m_row.m_attr_value_length)
set_field_varchar_utf8(f, m_row.m_attr_value,
m_row.m_attr_value_length);
else
f->set_null();
break ;
case FO_ORDINAL_POSITION:
set_field_ulong(f, m_row.m_ordinal_position);
break ;
default :
assert(false );
}
}
}
return 0 ;
}
bool
table_session_connect::thread_fits(PFS_thread *thread)
{
return true ;
}
Messung V0.5 in Prozent C=95 H=96 G=95
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland