You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This isn't so much of an issue, but rather an addition to the JSON parser for GetJSONFieldOrObjectOrArray (Ln 57200) and GetJSONField (Ln 56833).
I am using mORMot v1.18 (I don't have an exact build number, but I have compared against latest SynCommons file).
I was having difficulty handling boolean values returned from Postgresql 10.19.
PG was returning booleans as t or f
The values were not wrapped in quotes in the JSON so they were not being handled as text.
I have modified my local SynCommons.pas to parse these t / f values the same way true / false are parsed.
Apologies for the full method posts. I'm not sure how to submit it otherwise.
The changes are near to the bottom sections of the methods. Comments start with // added
I hope this helps others with handling Postgresql integration.
GetJSONField
// decode a JSON field into an UTF-8 encoded buffer, stored inplace of input bufferfunctionGetJSONField(P: PUTF8Char; out PDest: PUTF8Char;
wasString: PBoolean; EndOfObject: PUTF8Char; Len: PInteger): PUTF8Char;
var D: PUTF8Char;
c4,surrogate,j: integer;
c: AnsiChar;
b: byte;
jsonset: PJsonCharSet;
{$ifdef CPUX86NOTPIC} tab: TNormTableByte absolute ConvertHexToBin;
{$else} tab: PNormTableByte; {$endif}label slash,num,lit;
begin// see http://www.ietf.org/rfc/rfc4627.txtif wasString<>nilthen
wasString^ := false; // not a string by defaultif Len<>nilthen
Len^ := 0; // avoid buffer overflow on parsing error
PDest := nil; // PDest=nil indicates parsing error (e.g. unexpected #0 end)
result := nil;
if P=nilthen exit;
if P^<=''thenrepeat inc(P); if P^=#0then exit; until P^>'';
case P^ of'"': begin// " -> unescape P^ into D^if wasString<>nilthen
wasString^ := true;
inc(P);
result := P;
D := P;
repeat
c := P^;
if c=#0then exit elseif c='"'then break elseif c='\'thengoto slash;
inc(P);
D^ := c;
inc(D);
continue;
slash:inc(P); // unescape JSON string
c := P^;
if (c='"') or (c='\') thenbegin
lit: inc(P);
D^ := c; // most common case
inc(D);
continue;
endelseif c=#0then
exit else// to avoid potential buffer overflow issue on \#0if c='b'then
c := #8elseif c='t'then
c := #9elseif c='n'then
c := #10elseif c='f'then
c := #12elseif c='r'then
c := #13elseif c='u'thenbegin// inlined decoding of '\u0123' UTF-16 codepoint(s) into UTF-8{$ifndef CPUX86NOTPIC}tab := @ConvertHexToBin;{$endif}
c4 := tab[ord(P[1])];
if c4<=15thenbegin
b := tab[ord(P[2])];
if b<=15thenbegin
c4 := c4 shl4;
c4 := c4 or b;
b := tab[ord(P[3])];
if b<=15thenbegin
c4 := c4 shl4;
c4 := c4 or b;
b := tab[ord(P[4])];
if b<=15thenbegin
c4 := c4 shl4;
c4 := c4 or b;
case c4 of0: begin
D^ := '?'; // \u0000 is an invalid value
inc(D);
end;
1..$7f: begin
D^ := AnsiChar(c4);
inc(D);
end;
$80..$7ff: begin
D[0] := AnsiChar($C0 or (c4 shr6));
D[1] := AnsiChar($80or (c4 and $3F));
inc(D,2);
end;
UTF16_HISURROGATE_MIN..UTF16_LOSURROGATE_MAX:
if PWord(P+5)^=ord('\')+ord('u') shl8thenbegin
inc(P,6); // optimistic conversion (no check)
surrogate := (ConvertHexToBin[ord(P[1])] shl12)+
(ConvertHexToBin[ord(P[2])] shl8)+
(ConvertHexToBin[ord(P[3])] shl4)+
ConvertHexToBin[ord(P[4])];
case c4 of// inlined UTF16CharToUtf8()
UTF16_HISURROGATE_MIN..UTF16_HISURROGATE_MAX:
c4 := ((c4-$D7C0)shl10)+(surrogate xor UTF16_LOSURROGATE_MIN);
UTF16_LOSURROGATE_MIN..UTF16_LOSURROGATE_MAX:
c4 := ((surrogate-$D7C0)shl10)+(c4 xor UTF16_LOSURROGATE_MIN);
end;
case c4 of0..$7ff: b := 2;
$800..$ffff: b := 3;
$10000..$1FFFFF: b := 4;
$200000..$3FFFFFF: b := 5;
else b := 6;
end;
for j := b-1downto1dobegin
D[j] := AnsiChar((c4 and $3f)+$80);
c4 := c4 shr6;
end;
D^ := AnsiChar(Byte(c4) or UTF8_FIRSTBYTE[b]);
inc(D,b);
endelsebegin
D^ := '?'; // unexpected surrogate without its pair
inc(D);
end;
elsebegin
D[0] := AnsiChar($E0 or (c4 shr12));
D[1] := AnsiChar($80or ((c4 shr6) and $3F));
D[2] := AnsiChar($80or (c4 and $3F));
inc(D,3);
end;
end;
inc(P,5);
continue;
end;
end;
end;
end;
c := '?'; // bad formated hexa number -> '?0123'end;
goto lit;
until false;
// here P^='"'
D^ := #0; // make zero-terminatedif Len<>nilthen
Len^ := D-result;
inc(P);
if P^=#0then
exit;
end;
'0':
if P[1] in ['0'..'9'] then// 0123 excluded by JSON!
exit else// leave PDest=nil for unexpected endgoto num;// may be 0.123'-','1'..'9': begin// numerical field: all chars before end of field
num:result := P;
jsonset := @JSON_CHARS;
repeatifnot (jcDigitFloatChar in jsonset[P^]) then
break;
inc(P);
until false;
if P^=#0then
exit;
if Len<>nilthen
Len^ := P-result;
if P^<=''thenbegin
P^ := #0; // force numerical field with no trailing ' '
inc(P);
end;
end;
'n':
if (PInteger(P)^=NULL_LOW) and (jcEndOfJSONValueField in JSON_CHARS[P[4]]) thenbegin
result := nil; // null -> returns nil and wasString=falseif Len<>nilthen
Len^ := 0; // when result is converted to string
inc(P,4);
endelse
exit;
'f':
if (PInteger(P+1)^=FALSE_LOW2) and (jcEndOfJSONValueField in JSON_CHARS[P[5]]) thenbegin
result := P; // false -> returns 'false' and wasString=falseif Len<>nilthen
Len^ := 5;
inc(P,5);
endelseif (jcEndOfJSONValueField in JSON_CHARS[P[1]]) thenbegin// added parsing for singular unquoted 'f' boolean value
Result := P;
if Len<>nilthen
Len^ := 1;
inc(P, 1);
endelse
exit;
't':
if (PInteger(P)^=TRUE_LOW) and (jcEndOfJSONValueField in JSON_CHARS[P[4]]) thenbegin
result := P; // true -> returns 'true' and wasString=falseif Len<>nilthen
Len^ := 4;
inc(P,4);
endelseif (jcEndOfJSONValueField in JSON_CHARS[P[1]]) thenbegin// added parsing for singular unquoted 't' boolean value
Result := P;
if Len<>nilthen
Len^ := 1;
inc(P, 1);
endelse
exit;
else
exit; // PDest=nil to indicate errorend;
jsonset := @JSON_CHARS;
whilenot (jcEndOfJSONField in jsonset[P^]) dobeginif P^=#0then
exit; // leave PDest=nil for unexpected end
inc(P);
end;
if EndOfObject<>nilthen
EndOfObject^ := P^;
P^ := #0; // make zero-terminated
PDest := @P[1];
if P[1]=#0then
PDest := nil;
end;
GetJSONFieldOrObjectOrArray
functionGetJSONFieldOrObjectOrArray(var P: PUTF8Char; wasString: PBoolean;
EndOfObject: PUTF8Char; HandleValuesAsObjectOrArray: Boolean;
NormalizeBoolean: Boolean; Len: PInteger): PUTF8Char;
varValue: PUTF8Char;
wStr: boolean;
begin
result := nil;
if P=nilthen
exit;
while ord(P^) in [1..32] do inc(P);
if HandleValuesAsObjectOrArray and (P^ in ['{','[']) thenbeginValue := P;
P := GotoNextJSONObjectOrArray(P);
if P=nilthen
exit; // invalid contentif Len<>nilthen
Len^ := P-Value;
if wasString<>nilthen
wasString^ := false; // was object or arraywhile ord(P^) in [1..32] do inc(P);
if EndOfObject<>nilthen
EndOfObject^ := P^;
P^ := #0; // make zero-terminatedif P[1]=#0then
P := nilelse
inc(P);
result := Value;
endelsebegin
result := GetJSONField(P,P,@wStr,EndOfObject,Len);
if wasString<>nilthen
wasString^ := wStr;
ifnot wStr and NormalizeBoolean and (result<>nil) thenbeginif (PInteger(result)^=TRUE_LOW) or (result^='t') then// added check for 't' char boolean normalisation
result := pointer(SmallUInt32UTF8[1]) else// normalize true -> 1if (PInteger(result)^=FALSE_LOW) or (result^='f') then// added check for 'f' char boolean normalisation
result := pointer(SmallUInt32UTF8[0]) else// normalize false -> 0
exit;
if Len<>nilthen
Len^ := 1;
end;
end;
end;
The text was updated successfully, but these errors were encountered:
Hello,
This isn't so much of an issue, but rather an addition to the JSON parser for GetJSONFieldOrObjectOrArray (Ln 57200) and GetJSONField (Ln 56833).
I am using mORMot v1.18 (I don't have an exact build number, but I have compared against latest SynCommons file).
I was having difficulty handling boolean values returned from Postgresql 10.19.
PG was returning booleans as
t
orf
The values were not wrapped in quotes in the JSON so they were not being handled as text.
I have modified my local SynCommons.pas to parse these
t / f
values the same waytrue / false
are parsed.Apologies for the full method posts. I'm not sure how to submit it otherwise.
The changes are near to the bottom sections of the methods. Comments start with
// added
I hope this helps others with handling Postgresql integration.
GetJSONField
GetJSONFieldOrObjectOrArray
The text was updated successfully, but these errors were encountered: