Skip to content

Commit

Permalink
Merge pull request #83 from datajoint/stage
Browse files Browse the repository at this point in the history
Fix regression behavior with curley bracket parsing
  • Loading branch information
guzman-raphael authored May 27, 2021
2 parents cd31b05 + d45097a commit d161927
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 32 deletions.
Binary file modified distribution/mexa64/mym.mexa64
Binary file not shown.
Binary file modified distribution/mexmaci64/mym.mexmaci64
Binary file not shown.
Binary file modified distribution/mexw64/mym.mexw64
Binary file not shown.
118 changes: 90 additions & 28 deletions src/mym.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ void mexFunction(int nlhs, mxArray*plhs[], int nrhs, const mxArray*prhs[]) {
/*********************************************************************/
// Parse the result based on the first argument
enum querytype { OPEN, CLOSE, CLOSE_ALL, USE, STATUS, CMD, SERIALIZE, DESERIALIZE, VERSION } q;
char*query = NULL;
char* query = NULL;
if (nrhs<=jarg)
q = STATUS;
else {
Expand Down Expand Up @@ -817,41 +817,51 @@ void mexFunction(int nlhs, mxArray*plhs[], int nrhs, const mxArray*prhs[]) {
if (pcmp!=NULL)
mxFree(pcmp);
}
// Check that no placeholders are present in the query except for \{ and \}
char* parsedQueryString = (char*)mxCalloc(strlen(query), sizeof(char)); // Query string with escape character removed
size_t parsedQueryStringCurrentIndex = 0;

// Remove any white spaces at the beginning (NOTE for some reason mxFree crashes if this runs before it gets to the CMD block)
removeWhiteSpaceAtTheBeginning(query);
lengthOfQuery = strlen(query);

// Loop through the query string character by character
for (size_t i = 0; query[i] != '\0'; i++) {

if ((query[i] == '{' || query[i] == '}') && i != 0) {
if (query[i - 1] != '\\') {
// Curley bracket doesn't seem to be escaped thus throw and error
mxFree(parsedQueryString);
mexErrMsgTxt("The query contains placeholders, but no additional arguments!");
// Check if it is Create or Alter, if so then do curely bracket parsing
if (isSubstringFountAtTheBeginningCaseInsenstive(query, "CREATE") || isSubstringFountAtTheBeginningCaseInsenstive(query, "ALTER"))
{
// Check that no placeholders are present in the query except for \{ and \}
char* parsedQueryString = (char*)mxCalloc(strlen(query), sizeof(char)); // Query string with escape character removed
size_t parsedQueryStringCurrentIndex = 0;

// Loop through the query string character by character
for (size_t i = 0; query[i] != '\0'; i++) {

if ((query[i] == '{' || query[i] == '}') && i != 0) {
if (query[i - 1] != '\\') {
// Curley bracket doesn't seem to be escaped thus throw and error
mxFree(parsedQueryString);
mexErrMsgTxt("The query contains placeholders, but no additional arguments!");
}
else {
// Valid curley bracket thus add it to the parsedQueryString with the \ removed
parsedQueryStringCurrentIndex--;
parsedQueryString[parsedQueryStringCurrentIndex] = query[i];
}
}
else {
// Valid curley bracket thus add it to the parsedQueryString with the \ removed
parsedQueryStringCurrentIndex--;
// Non curley bracket thus add it to the parsedQueryString
parsedQueryString[parsedQueryStringCurrentIndex] = query[i];
}

// Increment the currentIndex counter
parsedQueryStringCurrentIndex++;
}
else {
// Non curley bracket thus add it to the parsedQueryString
parsedQueryString[parsedQueryStringCurrentIndex] = query[i];
}
// Add ending character
parsedQueryString[parsedQueryStringCurrentIndex] = '\0';

// Increment the currentIndex counter
parsedQueryStringCurrentIndex++;
// Update the query string
mxFree(query); // Free up the old string allocation
query = parsedQueryString;
lengthOfQuery = strlen(query); // Update the length of the query

}
// Add ending character
parsedQueryString[parsedQueryStringCurrentIndex] = '\0';

// Update the query string
mxFree(query); // Free up the old string allocation
query = parsedQueryString;
lengthOfQuery = strlen(query); // Update the length of the query


// Process flags
for (int i=nrhs-nb_flags; i < nrhs; ++i) {
if (strcasecmp(getstring(prhs[i]), ML_FLAG_BIGINT_TO_DOUBLE)==0) {
Expand Down Expand Up @@ -1179,6 +1189,58 @@ void mexFunction(int nlhs, mxArray*plhs[], int nrhs, const mxArray*prhs[]) {
}
}

void removeWhiteSpaceAtTheBeginning(char* string)
{
// Do a quick check at the start to see if any work needs to be done
if (!strlen(string) || !isspace(string[0]))
{
// The first character is not an empty space thus just return the orignal string
return;
}

// There are some white spaces that needs to be removed
size_t currentStringIndex = 1; // Offset of 1 due to the check at the beginning

// Loop through the string until a none whitespace character is found
for (; string[currentStringIndex] != '\0'; currentStringIndex++)
{
if (string[currentStringIndex] != ' ')
{
break;
}
}

char* sanitizeString = (char*)mxCalloc(strlen(string), sizeof(char));
size_t sanitizeStringIndex = 0;
// Copy the rest of the string over
for (; string[currentStringIndex] != '\0'; currentStringIndex++)
{
sanitizeString[sanitizeStringIndex] = string[currentStringIndex];
sanitizeStringIndex++;
}

// Replace the string
mxFree(string); // Free up the old string allocation
string = sanitizeString;
}

/**
* Helper function for checking if string subString is found at the start of string sourceString
* @param sourceString Source string to find subString at the start
* @param subString String target to look at the beginning of sourceString
* @returns Boolean answer if subString was found at the start of sourceString
*/
bool isSubstringFountAtTheBeginningCaseInsenstive(const char* sourceString, const char* subString)
{
for (size_t i = 0; subString[i] != '\0'; i++)
{
if (tolower(sourceString[i]) != tolower(subString[i]))
{
return false;
}
}
return true;
}

/*************************************SERIALIZE******************************************/
// Serialize a structure array
Expand Down
5 changes: 4 additions & 1 deletion src/mym.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
// mym version information
#define MYM_VERSION_MAJOR 2
#define MYM_VERSION_MINOR 8
#define MYM_VERSION_BUGFIX 1
#define MYM_VERSION_BUGFIX 2


// some local defintion
Expand All @@ -48,6 +48,7 @@
#include <mex.h> // Definitions for Matlab API
#include <zlib.h>
#include <math.h>
#include <ctype.h>
#include "matrix.h"

// We need a platform- and compiler-independent (rofl) fixed size 64 bit integer
Expand Down Expand Up @@ -105,6 +106,8 @@ mxArray* deserializeCell(const char* rpSerial, const size_t rlength);
int file_length(FILE *f); // get the size of a file in byte
unsigned long min_mysql_escape(char* rpout, const char* rpin, const unsigned long nin);
void safe_read_64uint(mwSize* dst, _uint64* src, size_t n);
bool isSubstringFountAtTheBeginningCaseInsenstive(const char* sourceString, const char* subString);
void removeWhiteSpaceAtTheBeginning(char* string);
//void safe_read_64uint(mwSize* dst, unsigned __int64* src, size_t n);

/**********************************************************************
Expand Down
24 changes: 21 additions & 3 deletions tests/TestDeclare.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,32 @@ function TestDeclare_delcareTable(testCase)
'false');

mym(conn1, ['create database `' testCase.PREFIX '_declare`']);
mym(['create table {S}(id int, data varchar(30) default null) COMMENT "\{username\}_\{subject_nickname\}"'], ...
mym([' create table {S}(id int, data varchar(30) default null) ' ...
'COMMENT "\{username\}_\{subject_nickname\}"'], ...
sprintf('`%s_%s`.`%s`', testCase.PREFIX, 'declare', 'test_table'));
query_string = mym(sprintf('SHOW CREATE TABLE `%s_%s`.`%s`', testCase.PREFIX, 'declare', 'test_table'));

if ~strfind(query_string.('Create Table'){1}, 'COMMENT=''{username}_{subject_nickname}''')
% Verify that comment got inserted correctly
query_string = mym(sprintf( ...
'SHOW CREATE TABLE `%s_%s`.`%s`', ...
testCase.PREFIX, ...
'declare', ...
'test_table'...
));
if ~strfind(query_string.(...
'Create Table'){1}, 'COMMENT=''{username}_{subject_nickname}''' ...
)
throw(MException('TestDeclare:invalidDeclareTable',...
'Table comments got inserted incorrectly'));
end

% Test if the curley bracket parsing mess with other data that it not suppose to
mym(sprintf( ...
'INSERT INTO `%s_%s`.`%s` (`id`, `data`) VALUES (0, ''}hello{'')', ...
testCase.PREFIX, ...
'declare', ...
'test_table' ...
));

mym(conn1, ['drop database `' testCase.PREFIX '_declare`']);
mym(conn1, 'close');
end
Expand Down

0 comments on commit d161927

Please sign in to comment.