Functions
To distinguish custom functions from inbuilt functions which are spelt in ALL CAPS, custom functions are spelt in CamelCase. This is to distinguish functions from procedures, which are spelt using underscores. Note: functions that READ SQL DATA from tables are also spelt with underscores. Note: in MySQL function and procedure names are case-insensitive, but this convention aids comprehension.
Deterministic
Authorisation
- IsEventScheduler()
- Returns true if the user is the event scheduler account.
- IsLocalCaller()
- Returns true if the user is logged in from a local shell.
- IsLocalRootCaller()
- Returns true if the user is logged in from a local shell and is authenticated as 'root'.
- IsRootCaller()
- Returns true if the user is authenticated as 'root'.
Cryptograpy
- GenerateSalt()
- Returns a 64 character salt string generated using SHA2.
- ComputeHash( $salt, $value )
- Returns the hash produced by hashing $value with $salt.
- MyDecrypt( $enckey, $value )
- Returns $value decrypted using AES using a decryption key generated by SHA2 hashing $enckey after it has been DES encrypted using a keyfile on disk.
- MyEncrypt( $enckey, $value )
- Returns $value encrypted using AES using a encryption key generated by SHA2 hashing $enckey after it has been DES encrypted using a keyfile on disk.
Date and time functions
- AsAppleTime( $datetime )
- Returns the current date and time in 'YYYY-MM-DD+HHTmm:ss.000+10:00:00' format.
- ConvertTo( $datetime )
- Returns the passed $datetime with one hours subtracted.
- ConvertToLocalTimeZone( $appletime )
- Returns the $appletime converted to the local timezone.
- ConvertWeekToDate( $year, $week )
- Returns the date of the Monday within the passed week.
- ConvertZoneToTime( $zone )
- Returns the timezone with plus or minus stripped, e.g. '+10:00' to '10:00'.
- DateOfNextDayname( $date, $dayname )
- Returns the date of the next day whose name matches $dayname.
- GetTime( $datetime )
- Returns the time part of a datetime.
- GetTimeZone()
- Returns the current timezone offset from GMT.
Geo functions
- DistanceBetween( $lat1, $lon1, $lat2, $lon2 )
- Returns the distance in km between the pair of coordinates - deprecated use MetresBetween or KilometresBetween.
- MetresBetween( $lat1, $lon1, $lat2, $lon2 )
- Returns the distance in metres between the pair of coordinates.
- KilometresBetween( $lat1, $lon1, $lat2, $lon2 )
- Returns the distance in km between the pair of coordinates.
Parameter handling
- CheckLimitOffset( $limit, $offset )
- Ensures that $limit and $offset are positive integers by adjusting them to high number of they are not.
String conversion
- DecodeHTMLEntities( $text )
- Returns text with some html entities converted back to original special characters.
String lists
- GetJth( $Text, $Delimiter, $J )
- Return the $Jth bit of text from $Test when using $Delimiter.
- ReplaceWith( $content, $delimiter, $equals, $dictionary )
- Replaces variables in content with values from dictionary.
Value testing
- IfEmpty( $text1, $text2 )
- If $text1 is null or an empty string when trimmed of whitespace returns $text2; otherwise $text1.
- IfNoDate( $date, $alternate )
- If $date is null or '0' return $alternate; otherwise return $date.
- IfNone( $date, $alternate )
- If $date is null or '0' return $alternate; otherwise return $date.
- IfVoid( $text1, $text2 )
- If $text1 = '' then return $text2; otherwise return $text1.
- IfZero( $id1, $id2 )
- If $id1 is zero, then return $id2; otherwise return $id1.
- IsNotEmpty( $text )
- If $text is null or an empty string when trimmed of whitesapce returns FALSE; otherwise TRUE.
- OrNull( $text1 )
- If $text1 is null or an empty string when trimmed of whitespace returns NULL; otherwise $text1.
Non-deterministic
Base functions - Files
- Base_Files_Exists_By_Kind( $sid, $USER, $kind )
- Returns true if a file of the specified 'kind' exists; otherwise false.
Base functions - Groups
- Base_Groups_Members_Contains( $GROUP_ID, $USER )
- Returns true if the specified 'USER' is a member of the specified 'GROUP'.
Base functions - Users
- Base_Users_Check_Password( $USER, $Password )
- Returns true if the passed 'Password' is correct for the passed 'USER'; otherwise false.
- Base_Users_Exists( $Email )
- Returns true if a user with the specified 'Email' exists; otherwise false.
- Base_Users_Get_Field( $USER, $field )
- Returns 'type' from 'users_uids' table for the specified 'USER' if 'type' is specified; otherwise empty string.
- Base_Users_Send_Resets_Exists( $token )
- Returns true if passed 'token' is valid; otherwise false.
- Base_Users_Verify_Credentials( $Email, $Password )
- Returns true if the passed credentails are valid; otherwise false.
Misc
- IsReadOnly()
- Returns true if global variable 'readonly' is true.
- LAST_INSERT_GUID()
- Returns the session variable '@LAST_INSERT_GUID'.
- ReadOnly()
- Returns true if global variable 'readonly' is true.
- Retrieve_Parameters_For( $database, $name )
- Returns the 'param_list' associated with the procedure $name defined in the $database.
Implementations
Authorisation
IsEventScheduler
DROP FUNCTION IsEventScheduler;
DELIMITER //
CREATE FUNCTION IsEventScheduler
()
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return (USER() = 'event_scheduler@localhost' );
END
//
DELIMITER ;
IsLocalCaller
DROP FUNCTION IsLocalCaller;
DELIMITER //
CREATE FUNCTION IsLocalCaller
()
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return NOT USER() = 'public@localhost' AND ((USER() LIKE '%@localhost') OR IsRootCaller() OR IsEventScheduler());
END
//
DELIMITER ;
is_local_root_caller
DROP FUNCTION IsLocalRootCaller;
DELIMITER //
CREATE FUNCTION IsLocalRootCaller
()
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return (USER() = 'root@localhost' );
END
//
DELIMITER ;
DROP FUNCTION IsRootCaller;
DELIMITER //
CREATE FUNCTION IsRootCaller
()
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return (USER() LIKE 'root@%' );
END
//
DELIMITER ;
DROP FUNCTION TranslateToOrgUsername;
DELIMITER //
CREATE FUNCTION TranslateToOrgUsername
(
$username TEXT,
$org_code TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $inbox TEXT DEFAULT '';
DECLARE $domain TEXT DEFAULT '';
DECLARE $provisional TEXT DEFAULT '';
SET $org_code = TRIM( $org_code );
SET $inbox = TRIM( GetJth( $username, '@', 1 ) );
SET $domain = TRIM( GetJth( $username, '@', 2 ) );
SET $provisional = CONCAT( $inbox, '+', $org_code, '@', $domain );
IF "" != $org_code AND "" != $inbox AND "" != $domain AND EXISTS
(
SELECT *
FROM base_users
WHERE user_deleted = 0
AND
(
email = $provisional
OR
email_provisional = $provisional
)
)
THEN
SET $username = $provisional;
END IF;
return $username;
END
//
DELIMITER ;
Cryptography
GenerateSalt
DROP FUNCTION GenerateSalt;
DELIMITER //
CREATE FUNCTION GenerateSalt
()
RETURNS CHAR(64)
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE salt CHAR(64);
SET salt = RAND();
SET salt = SHA2( salt, 256 );
return salt;
END
//
DELIMITER ;
ComputeHash
DROP FUNCTION ComputeHash;
DELIMITER //
CREATE FUNCTION ComputeHash
(
salt CHAR(64),
value TEXT
)
RETURNS CHAR(64)
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE enckey TEXT;
DECLARE string TEXT;
DECLARE hash CHAR(64);
#
# This value has now been hardcoded to deal with the deprecation
# of DES_ENCRYPT, which used to allow mingled encryption with an external key.
# This should be the value that would have been used if no external key was used.
#
SET enckey = "a514e1386e06661c1ca48b87dbada4d010b8149adca8b827c7fc23e2c49ad061";
SET string = CONCAT( enckey, salt, value );
SET hash = SHA2( string, 256 );
return hash;
END
//
DELIMITER ;
MyDecrypt
DROP FUNCTION MyDecrypt;
DELIMITER //
CREATE FUNCTION MyDecrypt
(
enckey TEXT,
encvalue TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE hashkey TEXT;
IF "" != encvalue THEN
#
# This value has now been hardcoded to deal with the deprecation
# of DES_ENCRYPT, which used to allow mingled encryption with an external key.
# This should be the value that would have been used if no external key was used.
#
SET hashkey = "a514e1386e06661c1ca48b87dbada4d010b8149adca8b827c7fc23e2c49ad061";
return AES_DECRYPT( UNHEX( encvalue ), hashkey );
ELSE
return "";
END IF;
END
//
DELIMITER ;
MyEncrypt
DROP FUNCTION MyEncrypt;
DELIMITER //
CREATE FUNCTION MyEncrypt
(
$enckey TEXT,
$value TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $hashkey TEXT;
IF "" != $value THEN
#
# This value has now been hardcoded to deal with the deprecation
# of DES_ENCRYPT, which used to allow mingled encryption with an external key.
# This should be the value that would have been used if no external key was used.
#
SET $hashkey = "a514e1386e06661c1ca48b87dbada4d010b8149adca8b827c7fc23e2c49ad061";
return HEX( AES_ENCRYPT( $value, $hashkey ) );
ELSE
return "";
END IF;
END
//
DELIMITER ;
RandomNumber
DROP FUNCTION RandomNumber;
DELIMITER //
CREATE FUNCTION RandomNumber
(
$max INT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $text TEXT DEFAULT '';
DECLARE $len INT DEFAULT 0;
SET $text = $max;
SET $len = LENGTH( $text );
SET $text = FLOOR( RAND() * $max );
return LPAD( $text, $len, '0' );
END
//
DELIMITER ;
Old_ComputeHash
DROP FUNCTION Old_ComputeHash; DELIMITER // CREATE FUNCTION Old_ComputeHash ( $salt INT(11), $value CHAR(99) ) RETURNS CHAR(16) SQL SECURITY INVOKER DETERMINISTIC BEGIN return MD5( concat($value, $salt) ); END // DELIMITER ;
Date and time functions
GetTimeZone
DROP FUNCTION GetTimeZone;
DELIMITER //
CREATE FUNCTION GetTimeZone
()
RETURNS CHAR(6)
DETERMINISTIC
BEGIN
DECLARE $diff TIME DEFAULT 0;
SET $diff = TIMEDIFF(NOW(), UTC_TIMESTAMP);
IF 0 <= $diff THEN
return CONCAT( "+", $diff );
ELSE
return $diff;
END IF;
END
//
DELIMITER ;
AsAppleTime
DROP FUNCTION AsAppleTime;
DELIMITER //
CREATE FUNCTION AsAppleTime
(
$datetime DATETIME
)
RETURNS TEXT
DETERMINISTIC
BEGIN
return CONCAT( DATE( $datetime ), "T", TIME( $datetime ), ".000", GetTimeZone() );
END
//
DELIMITER ;
ConvertZoneToTime
DROP FUNCTION ConvertZoneToTime;
DELIMITER //
CREATE FUNCTION ConvertZoneToTime
(
$zone CHAR(6)
)
RETURNS TIME
DETERMINISTIC
BEGIN
return CONVERT( REPLACE( $zone, "+", " " ), TIME );
END
//
DELIMITER ;
ConvertTo
DROP FUNCTION ConvertTo;
DELIMITER //
CREATE FUNCTION ConvertTo
(
$datetime DATETIME
)
RETURNS DATETIME
DETERMINISTIC
BEGIN
DECLARE $dx DATETIME DEFAULT 0;
SET $dx = DATE_SUB( $datetime, INTERVAL 1 HOUR );
return $dx;
END
//
DELIMITER ;
ConvertToLocalTimeZone
DROP FUNCTION ConvertToLocalTimeZone;
DELIMITER //
CREATE FUNCTION ConvertToLocalTimeZone
(
$appletime CHAR(29)
)
RETURNS DATETIME
DETERMINISTIC
BEGIN
# 2014-12-30T10:00:00.000+10:00
DECLARE $len INT;
DECLARE $tmp CHAR(29);
DECLARE $datetime DATETIME;
DECLARE $zone CHAR(6);
DECLARE $test TEXT;
SET $zone = "";
SET $test = "";
IF "" != $appletime THEN
SET $len = LENGTH( $appletime );
IF 10 = $len THEN
SET $datetime = CONVERT( $appletime, DATETIME );
SET $test = CONCAT_WS( "|", $datetime );
ELSEIF 19 = $len OR 23 = $len THEN
SET $tmp = REPLACE( $appletime, "T", " " );
SET $tmp = SUBSTRING( $tmp, 1, 19 );
SET $datetime = CONVERT( $tmp, DATETIME );
SET $test = CONCAT_WS( "|", $datetime );
ELSEIF 19 = $len OR 23 = $len THEN
SET $tmp = REPLACE( $appletime, "T", " " );
SET $tmp = SUBSTRING( $tmp, 1, 19 );
SET $datetime = CONVERT( $tmp, DATETIME );
SET $test = CONCAT_WS( "|", $datetime );
ELSEIF 25 <= $len THEN
SET $tmp = REPLACE( $appletime, "T", " " );
SET $tmp = SUBSTRING( $tmp, 1, 19 );
SET $datetime = CONVERT( $tmp, DATETIME );
SET $zone = SUBSTRING( $appletime, -6 );
SET $zone = REPLACE( $zone, ' ', '+' );
SET $datetime = CONVERT_TZ( $datetime, $zone, GetTimeZone() );
SET $test = CONCAT_WS( "|", $tmp, $datetime, $zone, GetTimeZone() );
#IF NULL = $datetime THEN
# SET $datetime = 0;
#END IF;
ELSE
SET $test = "Wrong length";
SET $datetime = 1;
END IF;
ELSE
SET $datetime = 2;
END IF;
return $datetime;
END
//
DELIMITER ;
ConvertToUTCTimeZone
DROP FUNCTION ConvertToUTCTimeZone;
DELIMITER //
CREATE FUNCTION ConvertToUTCTimeZone
(
$datetimezone TEXT
)
RETURNS DATETIME
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $sys_datetime DATETIME DEFAULT 0;
DECLARE $utc_datetime DATETIME DEFAULT 0;
SET $sys_datetime = ConvertToLocalTimeZone( $datetimezone );
SET $utc_datetime = CONVERT_TZ( $sys_datetime, '+10:00', '+00:00' );
return $utc_datetime;
END
//
DELIMITER ;
ConvertWeekToDate
DROP FUNCTION ConvertWeekToDate;
DELIMITER //
CREATE FUNCTION ConvertWeekToDate
(
$year YEAR,
$week INT(2)
)
RETURNS DATE
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $date_string TEXT;
DECLARE $start_of_week DATE;
SET $date_string = CONCAT( $year, $week, " MONDAY" );
return STR_TO_DATE( $date_string, '%X%V %W' );
END
//
DELIMITER ;
GetTime
DROP FUNCTION GetTime;
DELIMITER //
CREATE FUNCTION GetTime
(
$datetime TEXT
)
RETURNS TIME
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $time TIME DEFAULT 0;
DECLARE $one CHAR(10);
DECLARE $two CHAR(10);
DECLARE $use CHAR(10);
SET $one = GET_JTH( $datetime, " ", 1 );
SET $two = GET_JTH( $datetime, " ", 2 );
IF "" != $two THEN
SET $use = $two;
ELSE
SET $use = $one;
END IF;
IF 4 = LENGTH( $use ) THEN
SET $time = CONCAT( SUBSTR( $use, 1, 2 ), ":", SUBSTR( $use, 3, 2 ), ":00" );
ELSEIF 5 = LENGTH( $use ) THEN
SET $time = CONCAT( $use, ":00" );
ELSEIF 8 = LENGTH( $use ) THEN
SET $time = $use;
ELSE
SET $time = "12:59:59";
END IF;
return $time;
END
//
DELIMITER ;
DateOfNextDayname
DROP FUNCTION DateOfNextDayname;
DELIMITER //
CREATE FUNCTION DateOfNextDayname
(
$date DATE,
$dayname CHAR(3)
)
RETURNS DATE
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
#
# YEARWEEK( 2017-02-08 ) = '201706'
#
# STR_TO_DATE( CONCAT( '201706', ' ', 'Wed' ), '%X%V %a' ) = '2017-02-08'
#
# DATE_ADD( '2017-02-08', INTERVAL 1 WEEK ) = '2017-02-15'
#
DECLARE $date_of_dayname_in_this_week DATE DEFAULT 0;
DECLARE $date_of_next_dayname DATE DEFAULT 0;
SET $date_of_dayname_in_this_week = STR_TO_DATE( CONCAT( YEARWEEK( $date ), ' ', $dayname ), '%X%V %a' );
IF $date <= $date_of_dayname_in_this_week THEN
SET $date_of_next_dayname = $date_of_dayname_in_this_week;
ELSE
SET $date_of_next_dayname = STR_TO_DATE( CONCAT( YEARWEEK( DATE_ADD( $date, INTERVAL 1 WEEK ) ), ' ', $dayname ), '%X%V %a' );
END IF;
return $date_of_next_dayname;
END
//
DELIMITER ;
Geo functions
Finds the distance (in kilometers) between two points.
Based on: http:www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Deprecated use MetresBetween or KilometresBetween
DROP FUNCTION DistanceBetween;
DELIMITER //
CREATE FUNCTION DistanceBetween
(
$lat1 FLOAT,
$lon1 FLOAT,
$lat2 FLOAT,
$lon2 FLOAT
)
RETURNS FLOAT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $radius_earth_km INT DEFAULT 6371;
DECLARE $distance FLOAT;
DECLARE $sin1 FLOAT;
DECLARE $sin2 FLOAT;
DECLARE $cos1 FLOAT;
DECLARE $cos2 FLOAT;
DECLARE $power1 FLOAT;
DECLARE $power2 FLOAT;
SET $sin1 = SIN( ($lat1 - $lat2) * pi()/180/2);
SET $sin2 = SIN( ($lon1 - $lon2) * pi()/180/2);
SET $cos1 = COS( $lat1 * pi()/180);
SET $cos2 = COS( $lat2 * pi()/180);
SET $power1 = POWER( $sin1, 2 );
SET $power2 = POWER( $sin2, 2 );
SET $distance = $radius_earth_km * 2 * ASIN( SQRT( $power1 + $cos1 * $cos2 * $power2 ) );
return $distance;
END
//
DELIMITER ;
MetresBetween
DROP FUNCTION MetresBetween;
DELIMITER //
CREATE FUNCTION MetresBetween
(
$lat1 FLOAT,
$lon1 FLOAT,
$lat2 FLOAT,
$lon2 FLOAT
)
RETURNS INT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return CEIL( KilometresBetween( $lat1, $lon1, $lat2, $lon2 ) * 1000 );
END
//
DELIMITER ;
KilometresBetween
DROP FUNCTION KilometresBetween;
DELIMITER //
CREATE FUNCTION KilometresBetween
(
$lat1 FLOAT,
$lon1 FLOAT,
$lat2 FLOAT,
$lon2 FLOAT
)
RETURNS FLOAT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return DistanceBetween( $lat1, $lon1, $lat2, $lon2 );
END
//
DELIMITER ;
String functions
Base64Decode
DROP FUNCTION Base64Decode;
DELIMITER //
CREATE FUNCTION Base64Decode
(
$text LONGTEXT
)
RETURNS LONGTEXT
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
return CAST( FROM_BASE64( $text ) AS CHAR );
END
//
DELIMITER ;
CallToString
DROP FUNCTION CallToString;
DELIMITER //
CREATE FUNCTION CallToString
(
$sep CHAR,
$list TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $ret TEXT DEFAULT '';
DECLARE $next TEXT DEFAULT '';
DECLARE $i INT DEFAULT 0;
DECLARE $count INT DEFAULT 0;
#
# Determine the number of separators and therefore parameters.
#
SET $count = LENGTH( $list ) - LENGTH( REPLACE( $list, $sep, "" ) ) + 1;
WHILE $i < $count
DO
SET $i = $i + 1;
SET $next = GetJth( $list, $sep, $i );
IF $i = 1 THEN
IF $next = "" THEN
SET $ret = NULL; # NULL
ELSE
SET $ret = CONCAT( $ret, $next, '(' ); # Magic(
END IF;
ELSE
IF $i = $count AND $i = 2 THEN
SET $ret = CONCAT( $ret, ")" ); # Magic()
ELSEIF $i = 2 THEN
SET $ret = CONCAT( $ret, " '", $next, "'" ); # Magic( 'XXX'
ELSEIF $i > 2 AND $i < $count THEN
SET $ret = CONCAT( $ret, ", '", $next, "'" ); # Magic( 'XXX', 'YYY'
ELSEIF $i = $count THEN
SET $ret = CONCAT( $ret, ", '", $next, "' )" ); # Magic( 'XXX', 'YYY' )
END IF;
END IF;
END WHILE;
return $ret;
END
//
DELIMITER ;
DecodeHTMLEntities
DROP FUNCTION DecodeHTMLEntities;
DELIMITER //
CREATE FUNCTION DecodeHTMLEntities
(
$text LONGTEXT
)
RETURNS LONGTEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
SET $text = REPLACE( $text, '&', '!!AMP!!' );
IF INSTR( $text, '&' ) THEN
SET $text = REPLACE( $text, ''', "'" );
SET $text = REPLACE( $text, ''', "'" );
SET $text = REPLACE( $text, '’', "'" );
SET $text = REPLACE( $text, '"', '"' );
SET $text = REPLACE( $text, '<', '<' );
SET $text = REPLACE( $text, '>', '>' );
SET $text = REPLACE( $text, ' ', ' ' );
END IF;
SET $text = REPLACE( $text, '!!AMP!!', '&' );
return $text;
END
//
DELIMITER ;
Empty
DROP FUNCTION Empty;
DELIMITER //
CREATE FUNCTION Empty
(
$text LONGTEXT
)
RETURNS BOOL
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
return ISNULL( $text ) OR "" = TRIM( $text );
END
//
DELIMITER ;
Get Jth
MySQL SQL Stored Procedures do not provide support for any kind of arrays (other than creating tables), so, unsurprisingly, there are no array handling functions.
To get around this limitation, strings with delimiters can be used to store lists of items. The 'GET_JTH' function below returns such an item from the a list.
Note, the first element of a list corresponds to the index 1. This is to remain consistent with other MySQL functions that treat 1 as the first element.
DROP FUNCTION GetJth;
DELIMITER //
CREATE FUNCTION GetJth
(
$Text LONGTEXT,
$Delimiter TEXT,
$I INT(11)
)
RETURNS LONGTEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $tmp LONGTEXT DEFAULT '';
DECLARE $ret LONGTEXT DEFAULT '';
DECLARE $test LONGTEXT DEFAULT '';
IF 0 = LENGTH( $Delimiter ) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'EMPTY_DELIMITER';
END IF;
#
# Compare whether substring returned is same for i and i-1.
# If so have run out of components, set return as "".
#
SET $tmp = SUBSTRING_INDEX( $Text, $Delimiter, $I );
SET $test = SUBSTRING_INDEX( $Text, $Delimiter, $I - 1 );
IF $tmp != $test THEN
SET $ret = SUBSTRING_INDEX( $tmp, $Delimiter, -1 );
END IF;
RETURN $ret;
END
//
DELIMITER ;
ReplaceWith
Replace variables names adorned with percentage characters (i.e., %variable%) with the corresponding values present within the string encoded dictionary. The encoding of the dictionary is:
DICTIONARY := KEYPAIR, [DELIMITER, KEYPAIR] KEYPAIR := KEY, EQUALS, VALUE
Where KEY and VALUE can contain any ascii character except the DELIMITER, or EQUALS.
For example:
SELECT ReplaceWith( "Dear %given_name% %family_name%, Please following the link below.", ",", "=", "given_name=Daniel,family_name=Bradley" );
Or
SELECT ReplaceWith( "Dear %given_name% %family_name%, Please following the link below.", "|", ":", "given_name:Daniel|family_name:Bradley" );
DROP FUNCTION ReplaceWith;
DELIMITER //
CREATE FUNCTION ReplaceWith
(
$content LONGTEXT,
$delimiter TEXT,
$equals TEXT,
$dictionary LONGTEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $keypair LONGTEXT DEFAULT '';
DECLARE $key LONGTEXT DEFAULT '';
DECLARE $val LONGTEXT DEFAULT '';
DECLARE $i INT DEFAULT 1;
lp: WHILE TRUE DO
SET $keypair = GetJth( $dictionary, $delimiter, $i );
IF "" = $keypair THEN
LEAVE lp;
ELSE
SET $key = CONCAT( '%', TRIM( GetJth( $keypair, $equals, 1 ) ), '%' );
SET $val = TRIM( GetJth( $keypair, $equals, 2 ) );
SET $content = REPLACE( $content, $key, $val );
END IF;
SET $i = $i + 1;
END WHILE;
return $content;
END
//
DELIMITER ;
DROP FUNCTION ExtractUser;
DELIMITER //
CREATE FUNCTION ExtractUser
(
$email TEXT
)
RETURNS TEXT CHARSET latin1
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
SET $email = LOWER( $email );
SET $email = SUBSTRING_INDEX( $email, '@', 1 );
return CONCAT( '%', $email, '%' );
END
//
DELIMITER ;
DROP FUNCTION CalculatePasswordStrength;
DELIMITER //
CREATE FUNCTION CalculatePasswordStrength
(
$password TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $strength ENUM( "NONE", "WEAK", "MEDIUM", "STRONG", "ULTRA" );
DECLARE $length INT DEFAULT 0;
SET $strength = "NONE";
SET $length = LENGTH( $password );
IF $length > 20 THEN SET $strength = "ULTRA";
ELSEIF $length > 15 THEN SET $strength = "STRONG";
ELSEIF $length > 7 THEN SET $strength = "MEDIUM";
ELSE SET $strength = "WEAK";
END IF;
#
# Test for username in password
#
#IF EXISTS( SELECT * FROM base_users WHERE NOT email='' AND LOWER( $password ) LIKE ExtractUser( email ) ) THEN
# SET $strength = "WEAK";
#END IF;
IF "MEDIUM" = $strength THEN
#
# Optional site/policy specific tests
#
#
# Test for uppercase
#
#
# IF BINARY $password = BINARY UPPER( $password ) THEN
# SET $strength = "WEAK";
# END IF;
#
# Test for lowercase
#
#
# IF BINARY $password = BINARY LOWER( $password ) THEN
# SET $strength = "WEAK";
# END IF;
#
# Test for numeral
#
#
# IF NOT $password REGEXP '[0-9]' THEN
# SET $strength = "WEAK";
# END IF;
#
# Test for symbol
#
#
# IF NOT $password REGEXP '~|`|!|@|#|\\$|%|\\^|&|\\*|\\(|\\)|_|-|\\+|=|\\{|\\}|\\[|\\]|\\||:|;|"|\'|<|,|>|\\.|\\?|/' THEN
# SET $strength = "WEAK";
# END IF;
SET @nop = 0;
END IF;
return $strength;
END
//
DELIMITER ;
DROP FUNCTION CalculatePasswordStrength_Old;
DELIMITER //
CREATE FUNCTION CalculatePasswordStrength_Old
(
$password TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $strength ENUM( "NONE", "WEAK", "MEDIUM", "STRONG", "ULTRA" );
DECLARE $length INT DEFAULT 0;
SET $length = LENGTH( $password );
IF $length > 20 THEN SET $strength = "ULTRA";
ELSEIF $length > 15 THEN SET $strength = "STRONG";
ELSEIF $length > 5 THEN SET $strength = "MEDIUM";
ELSE SET $strength = "WEAK";
END IF;
return $strength;
END
//
DELIMITER ;
DROP FUNCTION Title;
DELIMITER //
CREATE FUNCTION Title
(
$text TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $title TEXT DEFAULT '';
DECLARE $word TEXT DEFAULT '';
DECLARE $i INT DEFAULT 0;
SET $title = "";
REPEAT
SET $i = $i + 1;
SET $word = GetJth( $text, ' ', $i );
SET $title = CONCAT( $title, ' ', SUBSTRING( $word, 1, 1 ), LOWER( SUBSTRING( $word, 2 ) ) );
UNTIL "" = $word END REPEAT;
return TRIM( $title );
END
//
DELIMITER ;
DROP FUNCTION ParseInt;
DELIMITER //
CREATE FUNCTION ParseInt
(
$number TEXT
)
RETURNS INT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
SET $number = TRIM( $number );
IF "" = $number THEN
return NULL;
ELSE
SET $number = TRIM( LEADING '0' FROM $number );
IF "" = $number THEN
return 0;
ELSE
SET $number = CONVERT( $number, SIGNED );
IF $number = 0 THEN
return NULL;
ELSE
return $number;
END IF;
END IF;
END IF;
END
//
DELIMITER ;
DROP FUNCTION JSONExtractPath;
DELIMITER //
CREATE FUNCTION JSONExtractPath
(
$text TEXT,
$path TEXT
)
RETURNS TEXT
READS SQL DATA
BEGIN
DECLARE $value TEXT DEFAULT NULL;
DECLARE $json JSON;
IF JSON_VALID( $text ) THEN
SET $json = $text;
SET $value = JSON_UNQUOTE( JSON_EXTRACT( $json, $path ) );
END IF;
return $value;
END
//
DELIMITER ;
DROP FUNCTION ReplaceFirst;
DELIMITER //
CREATE FUNCTION ReplaceFirst
(
$input TEXT,
$search TEXT,
$replace TEXT
)
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE $pos INT DEFAULT 0;
SET $pos = LOCATE( $search, $input );
IF 0 = $pos THEN
RETURN $input;
ELSE
RETURN
CONCAT
(
SUBSTRING( $input, 1, $pos - 1 ),
$replace,
SUBSTRING( $input, $pos + LENGTH( $search ) )
);
END IF;
END
//
DELIMITER ;
DROP FUNCTION Slice;
DELIMITER //
CREATE FUNCTION Slice
(
$text TEXT,
$delimiter TEXT,
$first INT,
$last INT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $tmp TEXT DEFAULT '';
DECLARE $value TEXT DEFAULT NULL;
DECLARE $i INT DEFAULT 1;
REPEAT
IF $first <= $i AND $i <= $last THEN
SET $tmp = GetJth( $text, $delimiter, $i );
IF LENGTH( $tmp ) THEN
SET $value = CONCAT_WS( $delimiter, $value, $tmp );
END IF;
END IF;
SET $i = $i + 1;
UNTIL $i > $last END REPEAT;
return $value;
END
//
DELIMITER ;
Throw functions
Below we define various functions that will throw an sqlexception, which will most likely be passed back to user code.
The intent of this is to allow the separation of more serious issues to be identified that should be rectified immediately, and those issues related to user error.
The following functions will throw a user defined sql exception with the following values:
- Throw - 45000
- Info - 45000
- Notice - 45001
- Warning - 45002
- Error - 45003
Throw and Info are synonimous and should be used for user errors that are expected to be propagated back to the user.
Notice should be used for INVALID_AUTHORISATION type errors that are mainly due to the user being inactive and their session expirying.
Warning should be used for when a call's parameters don't pass validation. Ideally, the front-end will be modified to do the validation to prevent the situation from occurring.
Error should be used for unexpected errors that need to be addressed immediately, such as when:
- An APIKey is invalid or of the wrong type
- An unexpected state is encountered
- An unexpected case option is passed
- ???
Throw
DROP PROCEDURE Throw;
DELIMITER //
CREATE PROCEDURE Throw
(
$message TEXT
)
SQL SECURITY INVOKER
BEGIN
SET @message = $message;
SET @severity = "Unknown";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = $message;
END
//
DELIMITER ;
Info
DROP PROCEDURE Info;
DELIMITER //
CREATE PROCEDURE Info
(
$message TEXT
)
SQL SECURITY INVOKER
BEGIN
SET @message = $message;
SET @severity = "Info";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = $message;
END
//
DELIMITER ;
Notice
DROP PROCEDURE Notice;
DELIMITER //
CREATE PROCEDURE Notice
(
$message TEXT
)
SQL SECURITY INVOKER
BEGIN
SET @message = $message;
SET @severity = "Notice";
SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = $message;
END
//
DELIMITER ;
Warning
DROP PROCEDURE Warning;
DELIMITER //
CREATE PROCEDURE Warning
(
$message TEXT
)
SQL SECURITY INVOKER
BEGIN
SET @message = $message;
SET @severity = "Warning";
SIGNAL SQLSTATE '45002' SET MESSAGE_TEXT = $message;
END
//
DELIMITER ;
Error
DROP PROCEDURE Error;
DELIMITER //
CREATE PROCEDURE Error
(
$message TEXT
)
SQL SECURITY INVOKER
BEGIN
SET @message = $message;
SET @severity = "Error";
SIGNAL SQLSTATE '45003' SET MESSAGE_TEXT = $message;
END
//
DELIMITER ;
Value testing functions
CheckLimitOffset
DROP PROCEDURE CheckLimitOffset;
DELIMITER //
CREATE PROCEDURE CheckLimitOffset
(
INOUT $limit INT(11),
INOUT $offset INT(11)
)
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
IF "" = $limit THEN
SET $limit = 1000000;
END IF;
IF "" = $offset THEN
SET $offset = 0;
END IF;
END
//
DELIMITER ;
IfEmpty
DROP FUNCTION IfEmpty;
DELIMITER //
CREATE FUNCTION IfEmpty
(
$text1 TEXT,
$text2 TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF ISNULL($text1) OR '' = TRIM($text1) THEN
return $text2;
ELSE
return $text1;
END IF;
END
//
DELIMITER ;
IfNoDate
DROP FUNCTION IfNoDate;
DELIMITER //
CREATE FUNCTION IfNoDate
(
$date DATE,
$alternate DATE
)
RETURNS DATE
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF 0 = $date OR ISNULL($date) THEN
return $alternate;
ELSE
return $date;
END IF;
END
//
DELIMITER ;
IfNone
DROP FUNCTION IfNone;
DELIMITER //
CREATE FUNCTION IfNone
(
$date DATETIME,
$alternate DATETIME
)
RETURNS DATETIME
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF 0 = $date OR ISNULL($date) THEN
return $alternate;
ELSE
return $date;
END IF;
END
//
DELIMITER ;
IfVoid
DROP FUNCTION IfVoid;
DELIMITER //
CREATE FUNCTION IfVoid
(
$text1 TEXT,
$text2 TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF '' = $text1 THEN
return $text2;
ELSE
return $text1;
END IF;
END
//
DELIMITER ;
IfZero
DROP FUNCTION IfZero;
DELIMITER //
CREATE FUNCTION IfZero
(
$id1 INT(11),
$id2 INT(11)
)
RETURNS INT(11)
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF 0 = $id1 THEN
return $id2;
ELSE
return $id1;
END IF;
END
//
DELIMITER ;
IsDate
DROP FUNCTION IsDate;
DELIMITER //
CREATE FUNCTION IsDate
(
$date DATE
)
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF ISNULL( $date ) OR 0 = $date THEN
return FALSE;
ELSE
return TRUE;
END IF;
END
//
DELIMITER ;
IsDateTime
DROP FUNCTION IsDateTime;
DELIMITER //
CREATE FUNCTION IsDateTime
(
$datetime TIMESTAMP
)
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF ISNULL( $datetime ) OR 0 = $datetime THEN
return FALSE;
ELSE
return TRUE;
END IF;
END
//
DELIMITER ;
IsNotEmpty
If $text is null or an empty string when trimmed of whitesapce returns TRUE; otherwise FALSE.
DROP FUNCTION IsNotEmpty;
DELIMITER //
CREATE FUNCTION IsNotEmpty
(
$text TEXT
)
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
return NOT( ISNULL($text) OR '' = TRIM($text) );
END
//
DELIMITER ;
IsTime
DROP FUNCTION IsTime;
DELIMITER //
CREATE FUNCTION IsTime
(
$time TIME
)
RETURNS BOOL
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF ISNULL( $time ) THEN
return FALSE;
ELSE
return TRUE;
END IF;
END
//
DELIMITER ;
OrNull
DROP FUNCTION OrNull;
DELIMITER //
CREATE FUNCTION OrNull
(
$text TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
IF '' = TRIM( $text ) THEN
return NULL;
ELSE
return $text;
END IF;
END
//
DELIMITER ;
Base functions
Files functions
Base_Files_Exists_By_Kind
DROP FUNCTION Base_Files_Exists_By_Kind;
DELIMITER //
CREATE FUNCTION Base_Files_Exists_By_Kind
(
$Sid CHAR(64),
$USER INT(11),
$kind CHAR(30)
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
IF @@read_only THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'READ_ONLY';
ELSE
CALL Base_Users_Authorise_Sessionid( $Sid, @email, @USER, @idtype );
IF $USER = @USER OR "ADMIN" = @idtype THEN
return EXISTS( SELECT * FROM base_files WHERE USER=$USER AND kind=$kind );
ELSE
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'INVALID_AUTHORISATION';
END IF;
END IF;
END
//
DELIMITER ;
Groups Functions
Base_Groups_Members_Contains
DROP FUNCTION Base_Groups_Members_Contains;
DELIMITER //
CREATE FUNCTION Base_Groups_Members_Contains
(
$GROUP_ID INT,
$USER INT
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
return EXISTS( SELECT * FROM base_groups_members WHERE GROUP_ID=$GROUP_ID AND USER=$USER );
END
//
DELIMITER ;
Base_GroupID_From_USER
DROP FUNCTION Base_GroupID_From_USER;
DELIMITER //
CREATE FUNCTION Base_GroupID_From_USER
(
$USER INT
)
RETURNS INT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $GROUP_ID INT DEFAULT 0;
SELECT GROUP_ID
INTO $GROUP_ID
FROM base_groups_members
WHERE USER = $USER
ORDER BY USER
LIMIT 1;
return $value;
END
//
DELIMITER ;
Places Functions
Base Places Addresses Match
DROP FUNCTION Base_Places_Addresses_Match;
DELIMITER //
CREATE FUNCTION Base_Places_Addresses_Match
(
$PLACE1_ID INT,
$PLACE2_ID INT
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $PLACE_ID INT DEFAULT 0;
DECLARE $street_number TEXT DEFAULT '';
DECLARE $street TEXT DEFAULT '';
DECLARE $suburb TEXT DEFAULT '';
DECLARE $city TEXT DEFAULT '';
DECLARE $state TEXT DEFAULT '';
DECLARE $country TEXT DEFAULT '';
DECLARE $postal_code TEXT DEFAULT '';
SELECT PLACE_ID, street_number, street, suburb, city, state, country, postal_code
INTO $PLACE_ID, $street_number, $street, $suburb, $city, $state, $country, $postal_code
FROM base_places
WHERE PLACE_ID = $PLACE1_ID;
return EXISTS
(
SELECT *
FROM base_places
WHERE PLACE_ID = $PLACE2_ID
AND street_number = $street_number
AND street = $street
AND suburb = $suburb
AND city = $city
AND state = $state
AND country = $country
AND postal_code = $postal_code
);
END
//
DELIMITER ;
Presets Functions
Base Presets Get Value
DROP FUNCTION Base_Presets_Get_Value;
DELIMITER //
CREATE FUNCTION Base_Presets_Get_Value
(
$ORG_ID INT,
$preset_code TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $preset_value TEXT DEFAULT NULL;
SELECT
IF
(
preset_allow_override AND NOT Is_Empty( org_preset_override_value ),
org_preset_override_value,
preset_value
)
INTO $preset_value
FROM view_base_organisations_presets
WHERE ORG_ID = $ORG_ID
AND preset_code = $preset_code;
IF ISNULL( $preset_value ) THEN
SELECT preset_value
INTO $preset_value
FROM base_presets_values
LEFT JOIN base_presets USING (PRESET_ID)
WHERE preset_code = $preset_code
AND preset_value_default;
END IF;
return $preset_value;
END
//
DELIMITER ;
Templates Functions
Base_Templates_Retrieve_Txt
DROP FUNCTION Base_Templates_Retrieve_Txt;
DELIMITER //
CREATE FUNCTION Base_Templates_Retrieve_Txt
(
$template_name TEXT
)
RETURNS TEXT
READS SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE $template TEXT DEFAULT '';
SELECT CAST( FROM_BASE64( template_txt64 ) AS CHAR )
INTO $template
FROM base_templates
WHERE template_deleted = 0
AND template_name = $template_name
ORDER BY TEMPLATE_ID DESC
LIMIT 1;
return $template;
END
//
DELIMITER ;
Base_Templates_Retrieve_Htm
DROP FUNCTION Base_Templates_Retrieve_Htm;
DELIMITER //
CREATE FUNCTION Base_Templates_Retrieve_Htm
(
$template_name TEXT
)
RETURNS TEXT
READS SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE $template TEXT DEFAULT '';
SELECT CAST( FROM_BASE64( template_htm64 ) AS CHAR )
INTO $template
FROM base_templates
WHERE template_deleted = 0
AND template_name = $template_name
ORDER BY TEMPLATE_ID DESC
LIMIT 1;
return $template;
END
//
DELIMITER ;
Users Functions
Base_Users_Check_Password
DROP FUNCTION Base_Users_Check_Password;
DELIMITER //
CREATE FUNCTION Base_Users_Check_Password
(
$USER INT(11),
$Password CHAR(99)
)
RETURNS BOOLEAN
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $valid BOOLEAN DEFAULT FALSE;
DECLARE $email TEXT;
IF @@read_only THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'READ_ONLY';
ELSE
SELECT email INTO $email FROM base_users WHERE USER=$USER;
SET $valid = users_verify_credentials( $email, $Password );
END IF;
return $valid;
END
//
DELIMITER ;
Base_Users_Exists
DROP FUNCTION Base_Users_Exists;
DELIMITER //
CREATE FUNCTION Base_Users_Exists
(
$Email CHAR(99)
)
RETURNS BOOLEAN
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
return Exists( SELECT email FROM base_users WHERE user_deleted=0 AND email=$Email );
END
//
DELIMITER ;
Base_Users_Get_Field
DROP FUNCTION Base_Users_Get_Field;
DELIMITER //
CREATE FUNCTION Base_Users_Get_Field
(
$USER INT(11),
$field CHAR(99)
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $value TEXT DEFAULT '';
CASE $field
WHEN 'type' THEN SELECT type INTO $value FROM base_users_uids WHERE USER=$USER;
END CASE;
return $value;
END
//
DELIMITER ;
Base_Users_Send_Resets_Exists
DROP FUNCTION Base_Users_Send_Resets_Exists;
DELIMITER //
CREATE FUNCTION Base_Users_Send_Resets_Exists
(
$token CHAR(64)
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $exists BOOLEAN DEFAULT FALSE;
IF @@read_only THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'READ_ONLY';
ELSE
SET $exists = EXISTS( SELECT * FROM base_users_send_resets WHERE token=$token );
END IF;
return $exists;
END
//
DELIMITER ;
Base_Users_Send_Resets_Exists
DROP FUNCTION Base_Users_Send_Resets_Get_User;
DELIMITER //
CREATE FUNCTION Base_Users_Send_Resets_Get_User
(
$token CHAR(64)
)
RETURNS INT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $USER INT DEFAULT 0;
SELECT USER
INTO $USER
FROM base_users_send_resets
WHERE token=$token
ORDER BY USER
LIMIT 1;
return $USER;
END
//
DELIMITER ;
Base_Users_Verify_Credentials
DROP FUNCTION Base_Users_Verify_Credentials;
DELIMITER //
CREATE FUNCTION Base_Users_Verify_Credentials
(
$Email CHAR(99),
$Password CHAR(99)
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $ret BOOL;
DECLARE $salt TEXT;
DECLARE $phash1 TEXT;
DECLARE $phash2 TEXT;
SET $ret = False;
IF @@read_only THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'READ_ONLY';
ELSE
IF EXISTS( SELECT * FROM base_users WHERE email=$Email ) THEN
SELECT user_salt INTO $salt FROM base_users WHERE email=$Email;
SELECT password_hash INTO $phash1 FROM base_users WHERE email=$Email;
SET $phash2 = ComputeHash( $salt, $Password );
IF $phash1 = $phash2 THEN
SET $ret = True;
END IF;
END IF;
END IF;
return $ret;
END
//
DELIMITER ;
Base_Users_Sessions_Resolve_Sid
DROP FUNCTION Base_Users_Sessions_Resolve_Sid;
DELIMITER //
CREATE FUNCTION Base_Users_Sessions_Resolve_Sid
(
$sid_at_ip TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $sid TEXT DEFAULT '';
DECLARE $Xid TEXT DEFAULT '';
SET $Xid = SUBSTRING_INDEX( $sid_at_ip, '@', 1 );
SELECT sid INTO $sid
FROM base_users_sessions
WHERE
(
sid=$Xid AND ('' = csrf OR IsLocalCaller())
)
OR
(
(SUBSTRING( sid, 1, 32 ) = SUBSTRING( $Xid, 1, 32 ))
AND
(
(SUBSTRING( csrf, 1, 32 ) = SUBSTRING( $Xid, 33, 32 ))
OR
EXISTS
(
SELECT *
FROM base_web_connections
WHERE SUBSTRING( connection_csrf_token, 1, 32 ) = SUBSTRING( $Xid, 33, 32 )
AND NOW() < connection_csrf_expiry
)
)
);
return $sid;
END
//
DELIMITER ;
Base_Users_Sessions_Resolve_Sid
DROP FUNCTION Base_Users_Sessions_Resolve_User;
DELIMITER //
CREATE FUNCTION Base_Users_Sessions_Resolve_User
(
$sid TEXT
)
RETURNS INT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $AUTH_USER INT DEFAULT 0;
SELECT AUTH_USER
INTO $AUTH_USER
FROM base_users_sessions
WHERE sid = $Sid
ORDER BY created
LIMIT 1;
return $AUTH_USER;
END
//
DELIMITER ;
Base_Users_Sessions_Verify
DROP FUNCTION Base_Users_Sessions_Verify;
DELIMITER //
CREATE FUNCTION Base_Users_Sessions_Verify
(
$Sid TEXT
)
RETURNS BOOLEAN
READS SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE $expiry INT;
DECLARE $now INT;
DECLARE $ret BOOL DEFAULT FALSE;
SET $now = UNIX_TIMESTAMP();
SET $ret = False;
SELECT expiry INTO $expiry FROM base_users_sessions WHERE sid=$Sid;
IF $now < $expiry THEN
SET $ret = True;
END IF;
return $ret;
END
//
DELIMITER ;
Base_Users_User_From_EmailProvisional
DROP FUNCTION Base_Users_User_From_EmailProvisional;
DELIMITER //
CREATE FUNCTION Base_Users_User_From_EmailProvisional
(
$email_provisional TEXT
)
RETURNS INT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $USER INT DEFAULT 0;
SELECT USER
INTO $USER
FROM base_users
WHERE user_deleted = 0
AND email_provisional = $email_provisional
ORDER BY USER
LIMIT 1;
return $USER;
END
//
DELIMITER ;
Base_Web_Connections_Verify
DROP FUNCTION Base_Web_Connections_Verify;
DELIMITER //
CREATE FUNCTION Base_Web_Connections_Verify
(
$sid_at_ip TEXT
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $sid TEXT DEFAULT '';
SET $sid = GetJth( $sid_at_ip, '@', 1 );
RETURN EXISTS
(
SELECT *
FROM base_web_connections
WHERE connection_csrf_token = $sid
);
END
//
DELIMITER ;
Miscellaneous functions
Assert
DROP PROCEDURE Assert;
DELIMITER //
CREATE PROCEDURE Assert
(
$proc TEXT,
$type ENUM( 'INT', 'DATE', 'DATETIME', 'TEXT', 'TIME' ),
$name TEXT,
$value TEXT
)
SQL SECURITY INVOKER
BEGIN
DECLARE $throw BOOL DEFAULT 0;
CASE $type
WHEN 'INT' THEN IF 0 = $value THEN SET $throw = TRUE; END IF;
WHEN 'DATE' THEN IF 0 = Date_Decode( $value ) THEN SET $throw = TRUE; END IF;
WHEN 'DATETIME' THEN IF 0 = $value THEN SET $throw = TRUE; END IF;
WHEN 'TEXT' THEN IF "" = TRIM( $value ) THEN SET $throw = TRUE; END IF;
WHEN 'TIME' THEN IF ISNULL( Time_Decode( $value ) ) THEN SET $throw = TRUE; END IF;
WHEN 'TRUE' THEN IF "1" = $value THEN SET $throw = TRUE; END IF;
END CASE;
IF $throw THEN
SET @assert = CONCAT( $proc, ": INVALID_PARAMETERS(", $name, ")" );
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = @assert;
END IF;
END
//
DELIMITER ;
Assert_Email_Available
DROP FUNCTION Assert_Email_Available;
DELIMITER //
CREATE FUNCTION Assert_Email_Available
(
$email TEXT
)
RETURNS BOOLEAN
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
IF EXISTS
(
SELECT *
FROM base_users
WHERE user_deleted = 0
AND
(
TRIM( email ) LIKE TRIM( $email )
OR
TRIM( email_provisional ) LIKE TRIM( $email )
)
)
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sorry, that email is already associated with an account';
ELSE
return TRUE;
END IF;
END
//
DELIMITER ;
Authorise_App_APIKey
DROP FUNCTION Authorise_App_APIKey;
DELIMITER //
CREATE FUNCTION Authorise_App_APIKey
(
$apikey TEXT,
$apikey_type TEXT
)
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $apikey_part TEXT DEFAULT '';
DECLARE $ip_address TEXT DEFAULT '';
SET $apikey_part = GetJth( $apikey, '@', 1 );
SET $ip_address = GetJth( $apikey, '@', 2 );
return EXISTS
(
SELECT *
FROM base_apikeys
WHERE apikey_type = $apikey_type
AND apikey = TRIM( $apikey_part )
AND (ip_address = '' OR ip_address LIKE CONCAT( '%[', $ip_address, ']%' ))
);
END
//
DELIMITER ;
IsReadOnly
DROP FUNCTION IsReadOnly;
DELIMITER //
CREATE FUNCTION IsReadOnly
()
RETURNS BOOLEAN
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $read_only BOOLEAN DEFAULT 0;
SELECT @@global.read_only INTO $read_only;
return $read_only;
END
//
DELIMITER ;
LAST_INSERT_GUID
DROP FUNCTION LAST_INSERT_GUID;
DELIMITER //
CREATE FUNCTION LAST_INSERT_GUID
(
$text TEXT
)
RETURNS CHAR(36)
SQL SECURITY INVOKER
NO SQL
BEGIN
IF IsNotEmpty( $text ) THEN
SET @LAST_INSERT_GUID = $text;
END IF;
return @LAST_INSERT_GUID;
END
//
DELIMITER ;
ReadOnly
DROP FUNCTION ReadOnly;
DELIMITER //
CREATE FUNCTION ReadOnly
()
RETURNS BOOL
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $readonly BOOLEAN DEFAULT 0;
IF @@read_only THEN
SET $readonly = 1;
END IF;
return $readonly;
END
//
DELIMITER ;
DROP FUNCTION Retrieve_Parameters_For;
DELIMITER //
CREATE FUNCTION Retrieve_Parameters_For
(
$database CHAR(64),
$name CHAR(99)
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
return RetrieveParametersFor( $database, $name );
END
//
DELIMITER ;
RetrieveParametersFor
Retrieve_Parameters_For
DROP FUNCTION RetrieveParametersFor;
DELIMITER //
CREATE FUNCTION RetrieveParametersFor
(
$database CHAR(64),
$name CHAR(99)
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $ret TEXT DEFAULT NULL;
DECLARE $ver INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR 1142 -- ER_TABLEACCESS_DENIED_ERROR
BEGIN
return "DEACTIVATED";
END;
IF $database != DATABASE() THEN
return "DATABASE_MISMATCH";
END IF;
SET $ver = GetJth( @@VERSION, '.', 1 );
IF 5 = $ver OR @@VERSION LIKE '%Maria%' THEN
SELECT
param_list
INTO
$ret
FROM mysql.proc
WHERE db = $database
AND name = $name
AND type = 'PROCEDURE'
AND security_type = 'DEFINER'
AND
(
(
NOT JSON_VALID( COMMENT )
AND
(
comment LIKE "EXPORT%"
OR
comment LIKE "OPEN%"
OR
comment LIKE "PUBLIC%"
)
)
OR
(
JSON_VALID( COMMENT )
AND
(
JSONExtractPath( COMMENT, '$.Security' ) = 'Export'
OR
JSONExtractPath( COMMENT, '$.Security' ) = 'EXPORT'
OR
JSONExtractPath( COMMENT, '$.Security' ) = 'Public'
OR
JSONExtractPath( COMMENT, '$.Security' ) = 'PUBLIC'
)
)
)
ORDER BY modified DESC LIMIT 1;
return $ret;
ELSE
return RetrieveParametersFor_Slow( $database, $name );
END IF;
END
//
DELIMITER ;
DROP FUNCTION RetrieveParametersFor_Slow;
DELIMITER //
CREATE FUNCTION RetrieveParametersFor_Slow
(
$database CHAR(64),
$name CHAR(99)
)
RETURNS TEXT
SQL SECURITY INVOKER
READS SQL DATA
BEGIN
DECLARE $ret TEXT DEFAULT NULL;
IF EXISTS
(
SELECT *
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA = $database
AND ROUTINE_NAME = $name
AND ROUTINE_TYPE = 'PROCEDURE'
AND SECURITY_TYPE = 'DEFINER'
AND
(
ROUTINE_COMMENT = 'EXPORT'
OR
ROUTINE_COMMENT = 'PUBLIC'
)
)
THEN
SET SESSION group_concat_max_len = 102400;
SELECT
GROUP_CONCAT( parameter ORDER BY ORDINAL_POSITION ) INTO $ret
FROM
(
SELECT
SPECIFIC_SCHEMA,
SPECIFIC_NAME,
ORDINAL_POSITION,
CONCAT( ' ', PARAMETER_NAME, ' ', UPPER( DATA_TYPE ) ) AS parameter
FROM information_schema.parameters
WHERE SPECIFIC_SCHEMA = $database
AND SPECIFIC_NAME = $name
AND ORDINAL_POSITION > 0 # Ignore return
ORDER BY ORDINAL_POSITION
) AS S0
GROUP BY SPECIFIC_SCHEMA, SPECIFIC_NAME;
END IF;
return $ret;
END
//
DELIMITER ;
RoundUp
DROP FUNCTION RoundUp;
DELIMITER //
CREATE FUNCTION RoundUp
(
$value DOUBLE,
$places INT
)
RETURNS DOUBLE
SQL SECURITY INVOKER
DETERMINISTIC
BEGIN
DECLARE $increment DOUBLE DEFAULT 0;
DECLARE $working DOUBLE DEFAULT 0;
SET $increment = 1 / POW( 10, $places );
SET $working = TRUNCATE( $value, $places );
IF $value > $working THEN
return TRUNCATE( $working + $increment, $places );
ELSE
return $working;
END IF;
END
//
DELIMITER ;
Profile
DROP PROCEDURE Enable_Profiling;
DELIMITER //
CREATE PROCEDURE Enable_Profiling
()
SQL SECURITY INVOKER
BEGIN
UPDATE performance_schema.setup_instruments
SET
ENABLED = 'YES',
TIMED = 'YES';
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES';
END
//
DELIMITER ;
DROP PROCEDURE Profile_Call;
DELIMITER //
CREATE PROCEDURE Profile_Call
(
$call TEXT
)
SQL SECURITY INVOKER
BEGIN
DECLARE $THREAD_ID BIGINT(20) unsigned DEFAULT 0;
DECLARE $EVENT_ID BIGINT(20) unsigned DEFAULT 0;
DECLARE $TIMER_START BIGINT(20) unsigned DEFAULT 0;
DECLARE $TIMER_END BIGINT(20) unsigned DEFAULT 0;
SELECT THREAD_ID, EVENT_ID, TIMER_START, TIMER_END
INTO $THREAD_ID, $EVENT_ID, $TIMER_START, $TIMER_END
FROM performance_schema.events_statements_history_long
WHERE CURRENT_SCHEMA = DATABASE()
AND event_name = "statement/sql/call_procedure"
AND SQL_TEXT LIKE CONCAT( $call, '%' )
AND ISNULL(NESTING_EVENT_ID)
ORDER BY EVENT_ID DESC
LIMIT 1;
SELECT $THREAD_ID, $EVENT_ID, $TIMER_START, $TIMER_END;
SELECT
THREAD_ID,
EVENT_ID,
END_EVENT_ID,
EVENT_NAME,
TIMER_START,
TIMER_END,
CONCAT( TIMER_WAIT/1000000000, "ms" ) AS ms,
OBJECT_NAME,
NESTING_EVENT_ID,
NESTING_EVENT_TYPE,
NESTING_EVENT_LEVEL,
REPLACE( SUBSTRING( SQL_TEXT, 1, 50 ), '\n', ' ' ) AS Text
FROM performance_schema.events_statements_history_long
WHERE CURRENT_SCHEMA = DATABASE()
AND event_name = "statement/sql/call_procedure"
AND THREAD_ID = $THREAD_ID
AND $TIMER_START <= TIMER_START
AND TIMER_END <= $TIMER_END
ORDER BY EVENT_ID;
END
//
DELIMITER ;
DROP PROCEDURE Profile_Parent;
DELIMITER //
CREATE PROCEDURE Profile_Parent
(
$EVENT_ID BIGINT
)
SQL SECURITY INVOKER
BEGIN
DECLARE $THREAD_ID BIGINT(20) unsigned DEFAULT 0;
DECLARE $EVENT_ID BIGINT(20) unsigned DEFAULT 0;
DECLARE $TIMER_START BIGINT(20) unsigned DEFAULT 0;
DECLARE $TIMER_END BIGINT(20) unsigned DEFAULT 0;
SELECT THREAD_ID, EVENT_ID, TIMER_START, TIMER_END, NESTING_EVENT_ID
FROM performance_schema.events_statements_history_long
WHERE EVENT_ID = $EVENT_ID;
END
//
DELIMITER ;
DROP PROCEDURE ShowViewDependants;
DELIMITER //
CREATE PROCEDURE ShowViewDependants
(
$view TEXT
)
SQL SECURITY INVOKER
BEGIN
DECLARE $pattern TEXT DEFAULT '';
SET $pattern = CONCAT( '%`', $view, '`%' );
SELECT TABLE_NAME
FROM information_schema.VIEWS
WHERE TABLE_SCHEMA = DATABASE()
AND VIEW_DEFINITION LIKE $pattern
;
END
//
DELIMITER ;
DROP PROCEDURE FindFunction;
DELIMITER //
CREATE PROCEDURE FindFunction
(
$pattern TEXT
)
SQL SECURITY INVOKER
BEGIN
SELECT
db,
name,
Base64Decode( body )
FROM mysql.proc
WHERE type = 'FUNCTION'
AND db = DATABASE()
AND name LIKE $pattern
;
END
//
DELIMITER ;
DROP PROCEDURE FindFunctions;
DELIMITER //
CREATE PROCEDURE FindFunctions
(
$pattern TEXT
)
SQL SECURITY INVOKER
BEGIN
SELECT
db,
comment,
security_type,
sql_data_access,
is_deterministic,
name,
returns
FROM mysql.proc
WHERE type = 'FUNCTION'
AND db = DATABASE()
AND name LIKE $pattern
;
END
//
DELIMITER ;
DROP PROCEDURE FindProcedures;
DELIMITER //
CREATE PROCEDURE FindProcedures
(
$pattern TEXT
)
SQL SECURITY INVOKER
BEGIN
SELECT
db,
comment,
security_type,
name
FROM mysql.proc
WHERE db = DATABASE()
AND type = 'PROCEDURE'
AND name LIKE $pattern
ORDER BY comment, security_type, name;
END
//
DELIMITER ;