You are not logged in.
No, it is not yet official possible (only if you change source code), but it is on roadmap. See the last valid point about BriefCase model.
Hi, Arnaud.
I did small changes to the SQLite3Service unit (TService).
I only added common property ControlHandler for setting the callback handler and some minor changes to fit it properly in code.
If the handler is not set from "outside" then your hack is used.
So this "outside discipline" is some how similar to the SvcMgr.TService approach.
The difference is that our TService does not force you to subclassing (no abstract procedure), it could be easily used in composition scenario too (I moved DoCtrlHandle to the public visibility for that reason).
Anyway I think that this approach is good (it's just added choice, we lose nothing), even if the asm (automatic router
) code would be corrected.
This always works, because is just basic Pascal
.
I sent you code via mail (I don't want to bloat the forum
).
I'm not fan of bloated implementations either.
Your TService is some kind well wrapped direct Win API solution.
I'll definitely take your class as base (at first my implementation was as composition, now sub-classing fits better) and only change that callback portion to "manual" Pascal way (I do not understand enough of assembler to correct your "automatic" way
).
or am I missing something?
Arnaud, you already explained usage of TService and somebody (Mick) already comment it, that some features does not work.
I'll be more precise:
You are using assembler tricks to call method of class instance instead of plain (stdcall) procedure :
Srv.FStatusHandle := RegisterServiceCtrlHandler(pointer(Srv.fSName), Srv.FJumper);And this is just not working in my scenario (Delphi 2009, Vista as target). It looks that this jumper cannot run at all from service controller.
If I run this "jumper code" manually (from my code), then it works:
type
TCtrlHandler = procedure(CtrlCode: DWord); stdcall;
(...)
TCtrlHandler(Srv.FJumper)(SERVICE_STOPPED);If I use plain (stdcall) procedure, then it works from service controller too:
procedure MyDoCtrlHandle(Code: DWORD); stdcall;
begin
(...)
end;
(...)
Srv.FStatusHandle := RegisterServiceCtrlHandler(pointer(Srv.fSName), Addr(MyDoCtrlHandle));I really don't have a clue what is wrong, maybe is just simpler to have some "safe fallback" similar to SvcMgr.TService:
TServiceController = procedure(CtrlCode: DWord); stdcall;
(...)
TService = class(TDataModule)
(...)
function GetServiceController: TServiceController; virtual; abstract;This is less intuitive, but is more Pascal way
. I don't know if this problem is easy solvable for you or is it better to add some kind of safe fallback too.
Some suggestions from my personal experience:
1. It won't be easy trip if you want to use the framework "to the end"
2. As already told, framework is not RAD (forget quick designing) but SOA oriented (benefits come later). This is nice explained in SAD documentation.
3. For all-in-one applications with "tons" of GUI element, you rather stick with some RAD solution based on TDataSet. You have many (free and payable) out there, just search with google. You can do this kind of application with mORMot too, but believe me, you will be slower. Except if you use mORMot user interface generation and that fits your needs. Mine has been totally different, so I have done it, all by myself (takes time). If you are using (and used to) some advanced grid, this you'll be missing most.
4. Think in objects, (almost) forget SQL. If you are used of tons of hand written SQL sentences you can used them in mORMot too, but this is not the right way and you are mixing two approaches often prematurely. Sometimes you must mixed them if you want some benefits from database (if you use only one type of persistence) which are not included in framework at same level.
5. For multi-tier or huge and complex applications the SOA way is the right way. So here the mORMot wins or better say it, is worth all effort invested it.
1. Entry point is here http://synopse.info/fossil/wiki?name=SQLite3+Framework.
2. This follows you to the download page.
3. Download and Read SAD documentation (ok, you already did)
4. Download official code at http://synopse.info/files/SynopseSQLite3.zip or bleeding edge code from the source control web interface (read about it here)
5. Look at examples in ...\Synopse\SQLite3\Samples\
6. Investigate the code (and comments in code) "playing" with examples or with your "samples"
7. Search first in this forum, because many questions was already asked, then ask...
Iterate all of the points again and again
.
You can see, that this was discussed already too
.
Regarding xmldoc starts from here.
This was discussed at least in two topics:
First in favor to object.
And second, yes there are possible problems with them too.
Small example:
First one (Get*) returns name of column (fetching first 0 indexed row, data is from 1 on).
Second one first un-camels name and potentially gets localized version of that text, if you use SQLite3i18n unit.
var
table: TSQLTable;
i: integer;
(...)
for i := 0 to table.FieldCount - 1 do
begin
writeln('col '+IntToStr(i)+' has name '+string(table.GetS(0,i)));
writeln('col '+IntToStr(i)+' has caption '+table.GetCaption(0,i));
end;
(...) Yes it works and seems as more complete solution
.
Hi, Arnaud.
Since 20.7.2011 I didn't refreshed local copy of mORMot framework from your fossil repository, until today.
I got some unexpected behavior on my "test polygon", when calling FillRow after CreateAndFillPrepare. Inner TSQLTable is that way already fetched, so I want to reuse cached data for update. I'm doing something based on TSQLTableToGrid, so I need this "more general" approach versus ORM way.
_masterRec: TSQLRecord;
(...)
_masterRec.FillRow(nodeData^.RowNum); //cause of error: ID was set to 0
_masterRec.SetFieldValue('Acknowledged', '1');
_client.Update(_masterRec); //error: this line then fails
(...)The reason why the upper code does not work is in next code:
unit SQLite3Commons, line 11262
procedure TSQLRecordFill.Fill(aTableRow: PPUtf8CharArray);
var f: integer;
begin
if (self=nil) or (aTableRow=nil) then
exit;
for f := 0 to fTableMapCount-1 do
with fTableMap[f] do
if DestField=nil then
Dest.ID := GetInteger(aTableRow[TableIndex]) else
DestField^.SetValue(Dest,aTableRow[TableIndex]);
end;In database table are some columns which do not map to the published properties of my TSQLRecord descendant and they evaluate to the fTableMap[f].DestField=nil too, what is setting Dest.ID to false 0 value.
I changed condition:
if DestField=nil thento the (if the ID is set, don't set it any more):
if (DestField=nil) and (Dest.ID = 0) thenUpdate:
This is not ok, because if I call several times in a roll FillRow on same TSQLRecord, then the ID is not fetched.
Some other, better identification is needed (f=0 or first occurrence of DestField=nil) to distinguish between RowID/ID field and "not mapped" fields, which (I think so) always come after ID field. For me it works either solution, but you will now what is best in several cases which may appear.
Hello Arnaud.
In my application I'm using TGDIPages for report generation and I noticed that some procedures have fixed behavior (they are not "obeying" custom settings; the work via SaveLayout -> RestoreSavedLayout).
I know that I can easily derive my own class from it and provide different behavior. But it would be more proper if this is done already at TGDIPages.
E.g. DrawTitle and DrawTextAcrossCols have fixed behavior.
DrawTitle has fixed rule for Font size and alignment (forcing left align) via TitleFlags.
DrawTextAcrossCols is (recently) forcing via PrintColumnHeaders no word wrapping (WordWrapLeftCols := false).
I think that these procedures should by default be customizable via global settings using save\restore layout and the fixed one (with fixed layout) should be renamed if really needed . If this is not an option, because of existing code, then at least there should be provided custom alternatives (e.g. TitleFlags should be writable property or procedures with custom suffix should be introduced -> DrawTitleCustom).
This is just proposition
.
Thanks to you for finding the real issue
.
Now works as expected.
I already showed you with previous post.
What you are naming Database is named in my case as rest.
So lets repeat and complete with your variables
:
var
TableRole: TSQLTable;
sql: string;
begin
sql := StringToUTF8('your join sql here');
TableRole := TSQLTableDB.Create(Database,[TSQLUserRoles, TSQLUserRole], sql, false);
TSQLTableToGrid.Create(dgRoles, TableRole, Database);
end;That is all. You must first read the SAD documentation and take MainDemo as first reference and Arnaud code (and comments) as MASTER REFERENCE !
It is not the stretch part, because plain draw fails too:
BMP.Canvas.Draw(0,0, TMetaFile(Pages.Objects[i]));So, for now only your DrawEmfGdip does the job, when you wish to print as it is shown on the screen!
This is somehow related to the scaling of the "elements", because in BMP (print as bitmap) case
following code works well (copied from PaintPreview, case for GDI+):
rec := Rect(0,0,Bmp.Width,Bmp.Height);
if not ForceNoAntiAliased then
DrawEmfGdip(BMP.Canvas.Handle,TMetaFile(Pages.Objects[i]), rec,ForceInternalAntiAliased);and this does not (original code for ForcePrintAsBitmap in TGDIPages.PrintPages function), which does some stretching (scaling) - I'm guessing from the name of procedure:
BMP.Canvas.StretchDraw(Rect(0,0,Bmp.Width,Bmp.Height), TMetaFile(Pages.Objects[i]));and with pdf export must be same issue when using "metafile to pdf commands".
Hopefully this narrow the problem down...
For me this solution becomes from "show stopper" to "accepted workaround", because at least I need working printing (pdf export is fine feature, but not the requirement in my application).
I have been investigating what is wrong in output pdf. First I converted output pdf to plain pdf commands (/FlateDecode).
Then I moved the "invisible" text (Td command) via Y axis for some amount and the content was shown.
So obviously the content is overwritten via some "pdf object".
I thought that pdf content is wrongly generated, but then I used ForcePrintAsBitmap of TGDIPages and result was the same.
So the problem is already at TMetafile level.
Why is content rendered correctly in preview form, but not when flushed to the BMP via ForcePrintAsBitmap?
Flushing of PreviewSurfaceBitmap is obviously ok.
Arnaud do you have a clue what is going on?
Hello Arnaud.
I found some invalid behavior with PDF export when WordWrapLeftCols is used. Content rendered with ShowPreviewForm is correctly shown on the screen, but when exporting report to the pdf is done, all texts which are short (word wrapping is not needed) following the first column which needs word wrapping are "INVISIBLE" (they are there, if you try to copy data, but not visible ?!).
This code snippet will reproduce the issue:
(...)
WordWrapLeftCols := true;
AddColumns([10,22,22,22,22]);
AddColumnHeaders(['#','Two','Three','4','5'],true,true);
for i := 1 to 50 do
DrawTextAcrossCols([IntToStr(i),'Column '+IntToStr(i),
'This is some big text which must be justified on multiple lines. Text "four" and "five" will be invisible in pdf...',
'four','five']);
(...)As it's already written only short texts ('four', 'five') following at least one long text will be invisible in PDF output.
Please, could you look at it.
You will find the causing problem faster then me.
It is very simple if you use TSQLTable directly e.g.:
(...)
sql := StringToUTF8('select * from T1 left join T2 on ...');
table := SQLite3.TSQLTableDB.Create(rest,[TSQLT1, TSQLT2], sql, false);
(...)I think you could do it simply via direct call of EngineExecute('VACUUM') of TSQLRest instance.
But you should read first about VACUUM command, that you call it at proper time, synchronized on server side.
This is somehow related to the Delphi 2009 object (keyword) issue .
You can see that "TP is an object" which is inherited from other object. So the quick solution (for now) is that you copy all fields from source object to the target object and the demo works then in Delphi 2009 too.
You have one small lapsus (which is show stopper
) in SQLite3i18n at line 1904:
text := ppi^.GetGenericStringValue(comp);should be
old := ppi^.GetGenericStringValue(comp);In unit SQLite3i18n at procedure ExtractAllResources is possible stack overflow!
More precisely this happens at iterative procedure AddClass when you use e.g. "Master/Detail" approach with TSQLRecordMany, which contains as property "Source" object which contains this TSQLRecordMany...
My quick solution is that I check which classes were already iterated:
procedure ExtractAllResources(const EnumTypeInfo: array of pointer;
const Objects: array of TObject; const Records: array of TClass;
const CustomCaptions: array of WinAnsiString);
(...)
var F: Text;
(...)
clist: array of TClass;
ccount: integer;
procedure AddClass(C: TClass);
var i,j: integer;
(...)
cfound: boolean;
begin
if C=nil then
exit; // no RTTI information (e.g. reached TObject level)
cfound := false;
for j:=0 to ccount-1 do
if C = clist[j] then
begin
cfound := true;
break;
end;
if not cfound then
begin
clist[ccount] := C;
Inc(ccount);
if Length(clist) = ccount then
SetLength(clist, Length(clist) + 3);
end;
AddClass(C.ClassParent); // add parent properties first
CP := InternalClassProp(C);
if CP=nil then
exit;
P := @CP^.PropList;
for i := 1 to CP^.PropCount do begin // add all field names
AddOnceDynArray(WinAnsiString(TSQLRecord.CaptionName(@P^.ShortName)));
// for Delphi 2009/2010/XE: CaptionName converted into a WinAnsiString
with P^.PropType^^ do
case Kind of
tkClass: // add contained objects
begin
cfound := false;
for j:=0 to ccount - 1 do
if ClassType^.ClassType = clist[j] then
begin
cfound := true;
break;
end;
if not cfound then
AddClass(ClassType^.ClassType);
end;
(...)
begin
// all code below use *A() Win32 API -> only english=Ansi text is expected here
assign(F,ChangeFileExt(paramstr(0),'.messages'));
SetLength(buf,65536);
SetLength(clist, Length(Objects)+Length(Records));
ccount := 0;
(...)Leander007 wrote:You missed the first change:
Group: TGroupBox absolute C;Without this the code does not work, because you are assigning different "C" control.
I didn't miss this one, but the correct missing line was this one:
fFieldComponents[i] := Group;
With first code excerpt goes this too:
fFieldComponents[i] := C;
continue;I was not thinking about the "long" version, but only about upper comparison, because later you use continue word, so the flow control is changed and the "extra" code
if (C<>nil) and (C<>self) and (C<>Scroll) then beginis never reached in set case.
So It seems that you were using C only for common handling of controls and TGroupBox does not count in it.
From technical aspect usage of the upper is the same, but cleaner design is assigning Group, not the C.
Arnaud you made lapsus in 215dfe5ac7.
Unit SQLite3UIEdit
line 394:
if E^.MaxValue>31 then // up to 32 elements in tkSet (GetOrdValue)
SetMax := 31 else
SetMax := E^.MaxValue;
Sets := P^.GetOrdValue(aRecord);
E := P^.PropType^^.SetEnumType;should be:
Sets := P^.GetOrdValue(aRecord);
E := P^.PropType^^.SetEnumType;
if E^.MaxValue>31 then // up to 32 elements in tkSet (GetOrdValue)
SetMax := 31 else
SetMax := E^.MaxValue;I saw that you did some cleanup in this procedure
, but excluding this, is there any real difference with
Group: TGroupBox absolute C;approach as you did for other controls and this latest code when you assign Group directly?
coblongpamor, if you need really customized look of edit form, then don't use TRecordEditForm, but develop custom GUI by "hand" (using Delphi RAD approach) as is done in Main Demo in FileEdit.pas (TEditForm) and manipulate with TSQLRecord as you wish.
Looking at the code should be enough, because basics of the framework are used in it.
You missed the first change:
C: TWinControl;
Group: TGroupBox absolute C;Without this the code does not work, because you are assigning different "C" control.
You are still having minor compile errors in SQLite3i18n unit.
Please could you check version in fossil (I must synch each way when I download
), maybe you are having right working copy, but wrong check-in in fossil version control.
unit SQLite3i18n:
procedure ExtractAllResources...
line 2850 is
AddOnceDynArray(WinAnsiString(TSQLRecord.CaptionName(@P^.Name)));should be
AddOnceDynArray(WinAnsiString(TSQLRecord.CaptionName(@P^.ShortName)));line 2890 is
AddOnceDynArray(WinAnsiString(CaptionName(@P^.Name)));should be
AddOnceDynArray(WinAnsiString(CaptionName(@P^.ShortName)));Quick look through comments in your code give me the filling of only <summary> node usage and missing others (as see, seealso, param...), which are used in chm, MS Help 2, HTML and other help formats used as API description in Delphi IDE and similar.
E.g. automatically inserted template (with regions of course) with typing almost only ///:
{$REGION 'xmldoc'}
/// <summary>
/// Register a specified test to this class instance
/// </summary>
/// <param name="aMethod">Comment here the aMethod param</param>
/// <param name="aName">Comment here the aName param</param>
{$ENDREGION}
procedure Add(aMethod: TSynTestEvent; const aName: string);with excerpt of generated xml doc (which is really verbose, too verbose, but quickly generated by compiler and you can guess that all xml tags are not completely the same as in .NET, but this is not the problem):
(...)
<procedure name="Add" visibility="public">
<devnotes>
<summary>
Register a specified test to this class instance
</summary>
<param name="aMethod">
Comment here the aMethod param
</param>
<param name="aName">
Comment here the aName param
</param>
</devnotes>
<parameters>
<parameter name="aMethod" type="TSynTestEvent"/>
<parameter name="aName" type="string" paramflags="const"/>
</parameters>
</procedure>
(...)versus
/// register a specified test to this class instance
procedure Add(aMethod: TSynTestEvent; const aName: string);Xml Doc is indeed more verbose (with more information in this case) when used for commenting the code, but with using regions that is not any problem, because they are collapsible and you don't see this as nagging text.
-------------
I saw that you have some special tags in comments, but I don't know if they could achieve same effect as regular xml doc tags?
Are this comment tags used in your code described anywhere?
In SynProject you have some kind of version control, but is it possible (with minor work) to attach some 3rd version control, such as subversion or fossil
?
I'll definitely look at SynProject in details to become more familiar with used concepts. Then I can properly make a comment, what could be done to easily interface (or extend) with existing tools, practices...
Yes, that was my comment about "several calls to InheritsFrom, this could be changed"
, because I realized that fFieldComponents was not assigned for sets
.
I did not realized if commenting continue will break something, because I changed the flow control (dirty and long version) where is not set related.
I will test it later if all works with your new version.
Yes, that was my point, only replacing PasDoc parser with xml doc parser, what Delphi itself is already. So if they add some new feature to Pascal language, we don't feel this, because xml doc output format is consistent and parsing xml is very easy.
Don't forget not only that you are compatible with .NET commenting, but you get Help Insight, compiler warnings about wrong referenced "classes" and maybe refactoring tools too. In short Embercadero is enforcing Microsoft standards and they (both) make tools for us.
I think would be best to use the Delphi generated xml output and parse it to some intermediate format which would fit in SynProject.
This way we don't need custom parser implementation for xml comments in code, rather we parse the well formated generated xml from Delphi compiler.
In this way you have generated xml with all classes, functions, records even if you did not comment anything. You get all hierarchy and you could easily generate final documentation only for "elements" which are commented if you wish.
What you think about that?
I have test it your TRecordEditForm with sources dating 2011-06-11. I saw that sets (TGroupBox implementation) could not be editable (the result was not really set to the TSQLRecord on BtnSaveClick).
So I changed the code that it works (at least it looks like that
) and "render" properly and nothing else (several calls to InheritsFrom, this could be changed).
I have done four changes in SetRecord procedure:
procedure TRecordEditForm.SetRecord(aClient: TSQLRestClient;
aRecord: TSQLRecord; CSVFieldNames: PUTF8Char=nil; Ribbon: TSQLRibbon=nil;
FieldHints: string=''; FieldNamesWidth: integer=0; aCaption: string='');
var i,j, aID, Y, aHeight, aWidth, CW: integer;
(...)
C: TWinControl;
Group: TGroupBox absolute C; // -----------------------------------------------------> CHANGE 1
(...)
begin
(...)
sftSet: begin
(...)
for j := 0 to E^.MaxValue do
with TCheckBox.Create(Scroll) do begin // add set checkboxes
(...)
end;
inc(Y,Group.Height+12);
//continue; // --------------------------------------------------------------> CHANGE 2
end;
(...)
if (C<>nil) and (C<>self) and (C<>Scroll) then begin
(...)
if not C.InheritsFrom(TCheckBox) then
if C.InheritsFrom(TLabeledEdit) then begin
(...)
end else if not C.InheritsFrom(TGroupBox) then // -------------------------------> CHANGE 3
with TLabel.Create(Scroll) do begin // add label left-sided to the field
(...)
if C.InheritsFrom(TDateTimePicker) then begin
(...)
end
else if not C.InheritsFrom(TGroupBox) then // -----------------------------------> CHANGE 4
C.SetBounds(FieldNamesWidth,Y,200,22);
fFieldComponents[i] := C;
inc(Y,aHeight);
end;
end;
end;By mistake I named SynProject as Synopse
in my last post. I'm aware (from your description, not really used it) of your completeness of this documenting program.
Maybe is not totally proper that I opened different but somehow connected subject, when I mentioned XML (with XSLT you have the power needed) as possible output for documentation and at the same time I was talking about XML DOC comments, which are standard at least in Microsoft world.
I really like xml doc comments, because I don't take this kind of xml as evil (opposite from that I see SOAP as too verbose). If you have proper tools at your hand this is not the obstacle. With tools I mean, using regions to hide comments, auto generated templates (automatically extracted arguments...) for procedures and functions for example, help insight showing your comments in Delphi IDE, Delphi checks referencing comments integrity when compiling and I can bet that some tool is capable to refactor referencing comments when you e.g. rename class.
If I understand correctly you use modified PasDoc (as I know all old parsers brake on new features of Delphi language, so constant update of them is the must) for comment extraction and then you generate pro file.
As I see it, xml doc could be replacement (or the extra possibility) only for PasDoc parser (not as the whole) as intermediate format, which has well formed xml format and could be easily parsed and transformed into pro format (or could be used for totally different cases, because it is standardized...).
In short, if I want to comment code in xml doc and use the generated Delphi xml documentation output as source for SynProject, which parts need the change? Is it only the PasDoc parser or is the "picture" more complex?
If this is not too hard, maybe I can try and add support for Delphi generated XML documentation, which is the code (with or without comments) extraction only.
Maybe is even more reasonable to take XML approach as from Delphi 2006 there is option to generate XML documentation (same as in .NET) and could be used for extraction for code comments in future and could be combined with other XML output. What is really nice if you have some cross links (e.g. see, seealso ...) which points to some non existing type, you get warning on compilation.
Ok, if the comments in code are converted to the xml doc format, then documentation from code could not be generated with Delphi prior 2006 (maybe Doc-O-Matic Express...) with Delphi itself.
This are just some thoughts, because I already use (still experimental) in some projects Doc-O-Matic Express for xml doc conversion to the chm (html) help, but I want to work directly with Delphi xml doc and having some custom logic (as you did with Synopse) which works with "static" help pages or even with wiki approach.
With CnPack or GExperts (it's peaty that this auto commenting features are not included in Delphi by default as it is in Visual Studio) is very easy to quickly comment units, classes, procedures. I'm using regions to expand or collapse comments, that is very handy too.
{$REGION 'xmldoc'}
/// <summary>
/// Token importance degree. 0 is for informative message, 1 is alarm and so on.
/// </summary>
{$ENDREGION}
property AlarmType: integer read _alarmType write _alarmType;Yes, HTML would be better and user editable...
Maybe even better as custom XML (raw data) with some XSLT transformation to get HTML or some other output.
Arnaud, is it possible to generate pdf bookmarks when you generate sampledoc pdf-s?
It would be very helpful when navigating through growing documentation.
I didn't look yet through Synopse project, so I don't know if this is easy to do automatically or not.
As I understand you don't use your pdf engine for output pdf-s, instead output from pro file is word document (doc) and then you use pdf export from Word.
No , this is not correct. FieldName is name of field (column).
With test
if FieldName = '' then you know that the table is in CREATION faze (could be named OnCreateTable) and you can execute the trigger creation at this stage (Table is created, so create the trigger too). You don't need other checks (this is the benefit of this approach).
Just override mentioned procedure for each TSQLRecord descendant which needs trigger (your case) or something else.
You must provide whole DDL sentence for trigger creation in Server.EngineExecuteAll(WholeDDLneeded).
You don't need to check for trigger existence, because you know that is not yet created, so just call "create trigger...".
Forget RTTI, that was just used in my example.
You just need to override next procedure in your derived class in which you need the trigger on related table:
public
class procedure InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8); override;
(...)and then in implementation:
class procedure TSQLToken.InitializeTable(Server: TSQLRestServer;
const FieldName: RawUTF8);
begin
inherited InitializeTable(Server, FieldName);
if FieldName = '' then begin //'' empty string means that the table is in creation faze (alias OnCreateTable)...
//Here comes your code which initialize some table data (in my case Token table) or do something else
//You could create your trigger at this stage with Server.EngineExecuteAll
end;
end;This is the proper object way, but you can achieve the same goal in many ways.
I was using InitializeTable for filling the delphi enum in some reference table (on table creation), where the enum's could be translated (not i18n) in some other text.
Here is the way how the InitializeTable is used in my example:
TSQLToken = class(TSQLRecord)
(...)
public
class procedure InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8); override;
(...)and then in implementation
class procedure TSQLToken.InitializeTable(Server: TSQLRestServer;
const FieldName: RawUTF8);
var
(...)
begin
inherited InitializeTable(Server, FieldName);
if FieldName = '' then begin //'' is for table creation in e.g. CreateMissingTables
TI := TypeInfo(TSystemMessage);
AddEnumToTable(TI);
TI := TypeInfo(TPumpMessage);
AddEnumToTable(TI, true);
end;
end;I didn't really looked the code, just run the tests and look for results
.
Now all tests pass just fine.
I checked your latest code (/FontBBox independace), but it does not work, the test still fails on:
Check(H=$2636C99E);The fontbbox is still "/FontBBox [-628 -376 2000 1010 ]"
Yes indeed looks that PAnsiChar casting was guilty for hidden conversion.
Super
, now there is only one failing test left and that is the PDF check:
Unit SynSelfTest
813:
H := Hash32(MS.Memory,MS.Position);
Check( (H=$93D859A5) or (H=$9FB359A7) ); // Arial,Bold and Tahoma FontBBox
MS.SaveToFile(ChangeFileExt(paramstr(0),'.pdf'));Is the date below in resulting pdf correct?
/CreationDate (D:20100610191717)
/ModDate (D:20100610191717)
Is the webcontact01 mail or is web link in some page (that I can send you the resulting pdf for quick diff with yours expected one)?
Ok, I did not find where is webcontact01, but any way I think the file wont help much, because I already said which bytes are different from expected result and the issue exists prior JSON encoding.
When we read from database we get "97 233 231" sequence instead of "224 233 231". So it must be wrong writing to the database or reading from the database.
I will test it further in this days when I'll have spare time.
Moggco said that "next" test is solved in general way with chr(...) solution.
Strange is that this "direct file test" fails even when we use this approach (at least when used cp 1250, but assuming other coding will fail too).
Hm, next error is strange for me, you will get it much faster than me, what is going on.
Direct access file test failure:
When I look in Test1.json dump file, created with different exe-s (1252,1250), the only difference is in BLOB part:
Unit SQLite3
R.Bind(1,PAnsiChar(chr(224)+chr(233)+chr(231)+'dsjdsBLOB23'),14); // Bind Blob
(...)
JS := Demo.ExecuteJSON(Req); // get result in JSON format
FileFromString(JS,'Test1.json');
Check(Hash32(JS)=$221D7DBD,'Expected ExecuteJSON result not retrieved');//line 5623Here are JSON excerpts (Difference is in 2 Bytes in BLOB ?! Are we not forcing this with chr(...) to be correct, where is the problem?):
1250: "Mônet","YennZHNqZHNCTE9CMjM=",1840,1926,19, -> Ye is $59 $65
1252: "Mônet","4OnnZHNqZHNCTE9CMjM=",1840,1926,19, -> 4O is $34 $4F
Ok, with debugger I saw that sqlite3_column_blob api in
W.WrBase64(sqlite3_column_blob(Request,i),
sqlite3_column_bytes(Request,i),true);returned for those 3 Bytes next values for 1250:
$61 $E9 $E7 -> 97 233 231 //strange, the first one is incorrect?!
and for 1252:
$E0 $E9 $E7 -> 224 233 231 //all three are correct
My correction about code page.
TestSQL3 build in OS with code page set to 1252 runs all tests (excluding last PDF test) just fine in OS with code page set to e.g. 1250.
So the problem is in literals. All must be corrected as you did before with chr(number) in consistent way and all will work.
No this does not work, I think that there is no way to change system code page without restarting the OS.
All upper tests excluding this last post (TPdfDocumentGDI test) are code page related.
They fail if I change system locale code page to something else as 1252 (in my case 1250).
Only TPdfDocumentGDI test (last check) fails in all circumstances in which I run tests.
Yes, using break is the shortest one
.
With next PDF test I really don't have a clue what could be wrong and how to test it, because I don't know what to expect in intermediate steps.
Unit SynSelfTests
Check on line 792 is OK,
but the check on line 813 fails:
H := Hash32(MS.Memory,MS.Position); //MS.Position=6725, H=$93E059A5
Check( (H=$93D859A5) or (H=$9FB359A7) ); // Arial,Bold and Tahoma FontBBox