Sign in Join
Wiki copytemporary

ZMSQL: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# About
22
33*ZMSQL* is an open source and free, TBufDataset SQL enhanced in-memory database for Free Pascal (FPC), operating with semicolon-separated values flat text tables as a persistence store.
44
55This means you can use files to store your data but get the speed of in-memory processing. Completely written in Pascal, it has no dependencies on external libraries.
66
77ZMSQL package consists of three components:
88
991\. **TZMConnection** - describes "database" as folder containing CSV files, and some common properties for all datasets.
1010
11112\. **TZMQueryDataset** - an in-memory dataset (TBufDataset descendent) capable of loading/saving from CSV files, loading/executing SQL queries (via integrated JanSQL database engine) and loading data from any other datasets. ZMQueryDatasets also have integrated properties for easy setting master/detail filtration.
1212
13133\. **TZMReferentialKey** - component that describes relation between master and slave dataset for referential integrity (insert, update, delete).
1414
15154\. **TZMQueryBuilder** - visual query builder.
1616
1717ZMSQL offers:
1818
1919- Loading from and saving to flat text tables
2020- Use of SQL to query the data
2121- Copy data and schema from other datasets
2222- Option to predefine fielddefs or create it on-the fly
2323- Master/detail filtering
2424- Referential integrity
2525- Parameterized queries
2626- visual query builder (currently does not yet suppport non-standard janSQL statements, only standard SQL)
2727
2828The download contains the source code, some demo applications illustrating the features of the component as well as a readme.
2929
3030# Author
3131
3232\- Zlatko Matić (matalab@gmail.com); includes code from Jan Verhoeven and Martin Waldenburg.
3333
3434Contact Zlatko Matić ("tatamata" in Lazarus forum) by e-mail: matic.zlatko@gmail.com or matalab@gmail.com
3535
3636Contributors:
3737
3838- Mario Ferrari (mario.ferrari@edis.it)
3939- Edgar Fernando Rodriguez Pacheco (edgarrod71@gmail.com)
4040
4141# License
4242
4343Modified LGPL and MPL 1.1 license: static and dynamic linking both allowed, even in commercial applications. Please see the individual licenses in the source files for details.
4444
4545Contains:
4646
4747- ZMSQL units, including zmbufdataset.pas, zmconnection.pas, zmquerydataset.pas, zmreferentialkey.pas: FPC modified LPGL
4848- JanSQL units, including JanSQL.pas, janSQLExpression2.pas, janSQLStrings.pas, janSQLTokenizer.pas by Jan Verhoeven: Mozilla Public License Version 1.1 (MPL)
4949- mwStringHashList.pas by Martin Waldenburg: Mozilla Public License Version 1.1 (MPL)
5050
5151# Download
5252
5353The latest stable release can be found on *<http://sourceforge.net/projects/lazarus-ccr/files/zmsql/>*.
5454
5555# Published and Public properties and methods of TZMQueryDataset
5656
5757``` pascal
5858 public
5959 { Public declarations }
6060 procedure QueryExecute; //Executes SQL query defined in SQL property, on .csv files that are placed in folder defined in ZMConnection property. Resultset of select query is loaded into the the zmquerydataset (self).
6161 procedure PrepareQuery; //Prepares parameterized queries for execution: replaces parameters with parameter values for parameterized queries.
6262 procedure EmptyDataSet; //Deletes all records from dataset.
6363 procedure ClearDataSet; //Deletes records, fields and fielddefs.
6464 procedure CopyFromDataset (pDataset:TDataSet); //Copies schema and data from any TDataset.
6565 function SortDataset (const pFieldName:String):Boolean; //Ascending/Descending sorting of memory dataset.
6666 procedure LoadFromTable; //Loads data (or data and schema) from a .csv file (TableName.csv), set in property TableName, from path specified in ZMConnection property.
6767 procedure SaveToTable;overload; //Saves data and schema to a .csv file (TableName.csv), set in Tablename property, in path specified in ZMConnection property.
6868 procedure SaveToTable(pDecimaSeparator:Char);overload; //Saves data and schema to a .csv file (TableName.csv), set in Tablename property, in path specified in ZMConnection property.
6969 procedure CreateDynamicFieldsFromFieldDefs; // Creates fields from predefined fielddefs. To be used in design-time or run-time for memory dataset creation according to predefined fielddefs.
7070 procedure CreatePersistentFieldsFromFieldDefs; // Creates PERSISTENT fields from predefined fielddefs. To be used in design-time only.
7171 procedure MemoryDataSetOpen; //Executes CreateDynamicFieldsFromFieldDefs and set dataset to Active.
7272 constructor Create(AOwner: TComponent); override;
7373 destructor Destroy; override;
7474 //Properties needed for master/detail and referential integrity
7575 property MasterDataSetTo:TList read FMasterDataSetTo write SetMasterDataSetTo; // Defines master/detail relationship for purpose of master/detail filtration
7676 property MasterReferentialKeys:TList read FMasterReferentialKeys write SetMasterReferentialKeys;//Defines master/detail relationship for purpose of referential integrity
7777 property SlaveReferentialKeys:TList read FSlaveReferentialKeys write SetSlaveReferentialKeys; //Defines master/detail relationship for purpose of referential integrity
7878 property DisableMasterDetailFiltration:Boolean read FDisableMasterDetailFiltration write SetDisableMasterDetailFiltration; //Master/detail filrtation should be temporarily desabled during bulk inserts or updates...
7979 property OldRecord:TZMBufDataSet {TBufDataSet} read FOldRecord; //Last delete/insert/edit is preserved in this property.
8080 published
8181 { Published declarations }
8282 property ZMConnection:TZMConnection read FZMConnection write SetConnection; //Defines "database" folder path where .csv tables are placed. Instantiates JanSQL database engine.
8383 property SQL:TStrings read FSQL write SetSQL; //Unprepared SQL query text.
8484 property QueryExecuted:Boolean read FQueryExecuted write SetQueryExecuted; //"True" executes QueryExecute and loads resultset into dataset.
8585 property TableName:String read FTableName write SetTableName; //Name of .csv file (without extension) from which is data loaded by LoadFromTable and to which is data and schema saved by SaveToTable.
8686 property TableLoaded:Boolean read FTableLoaded write SetTableLoaded; //"True" executes LoadFromTable and loads resultset into dataset.
8787 property TableSaved:Boolean read FTableSaved write SetTableSaved; //"True" executes SaveToTable and saves dataset to .csv file defined in TableName property, placed in folder specified by ZMConnection property.
8888 property DynamicFieldsCreated:Boolean read FDynamicFieldsCreated write SetDynamicFieldsCreated; //"True" executes CreateDynamicFieldsFromFieldDefs, which creates fields from predefined fielddefs.
8989 property PeristentFieldsCreated:Boolean read FPersistentFieldsCreated write SetPersistentFieldsCreated; //"True" executes CreatePersistentFieldsFromFieldDefs, which creates PERSISTENT fields from predefined fielddefs.
9090 property MemoryDataSetOpened:Boolean read FMemoryDataSetOpened write SetMemoryDataSetOpened; //"True" executes CreateDynamicFieldsFromFieldDefs and activates dataset for editing.
9191 property PersistentSave:Boolean read FPersistentSave write SetPersistentSave; //If "True", insert/delete/edit will immediately be written to underlying .csv file. If "False", then dataset is only in-memory.
9292 property Parameters: TParams read FParameters write SetParameters; //Parameters for parameterized SQL text.
9393 //Master/detail filtration
9494 property MasterFields: TStrings read FMasterFields write SetMasterFields; //Fields in masterdatasource, (separated by ";") to be used for master/detail filtration.
9595 property MasterSource: TDataSource read FMasterSource write SetMasterSource;//Master datasource for master/detail filtration.
9696```
9797
9898# JanSQL SQL language
9999
100100janSQL database engine supports only a subset of standard SQL but the supported statements are sufficient for single-user desktop application.
101101
102102## Table updates
103103
104104janSQL loads tables automatically into memory when needed by a query. Any changes to tables (INSERT, UPDATE, DELETE) are performed in memory. Tables are saved to disk when you use the COMMIT statement. The only exceptions to this are the CREATE TABLE statement, where the new table is saved to disk immediately and the DROP TABLE statement, where the table is immediately deleted from both memory and disk.
105105
106106## Indexes
107107
108108janSQL does not use indexes. You will find that for single-user desktop applications running in memory there is no urgent need for indexes.
109109
110110## Case sensitivity
111111
112112janSQL is case-insensitive for its keywords: you can use both SELECT and select.
113113
114114## Non-standard
115115
116116janSQL has several non-standard SQL statements for manipulation of recordsets.
117117
118118- **ASSIGN TO**
119119- SAVE TABLE
120120- RELEASE TABLE
121121
122122**Compound Queries**
123123
124124You can execute **multiple queries in a batch**. Query expressions in a compound query must be separated by semi-colon. By using the non-standard **ASSIGN TO statement** you can store the result of a select query as a **named variable** that can be used in subsequent queries. This resembles SQL stored procedures in other database systems.
125125
126126SQL syntax
127127
128128A\) Data Definition Language
129129
130130CONNECT TO
131131
132132Connects to a database. In janSQL a database is a folder. Tables are stored in this folder as delimited text files with the .txt extension. Syntax: CONNECT TO 'absolute-folder-path'
133133
134134Example:
135135
136-`   connect to 'G:'  `\
136+```text
137+ connect to 'G:'
138+```
137139
138140Notes
139141
140142This is always the first statement that you use with janSQL. All other SQL statements require that the engine knows which folder to use.
141143
142144CREATE TABLE
143145
144146Creates a new table in the current catalog.
145147
146148Syntax:
147149
148-`CREATE TABLE tablename (field1,[fieldN])`
150+```text
151+CREATE TABLE tablename (field1,[fieldN])
152+```
149153
150154Example:
151155
152-`CREATE TABLE users (userid,username,accountname, accountpassword)`
156+```text
157+CREATE TABLE users (userid,username,accountname, accountpassword)
158+```
153159
154160Notes
155161
156162janSQL does not use fieldtypes. Everything is stored as text. Internally janSQL treats all data as variants. This means that in your SQL queries you can use fields pretty much the way you want to.
157163
158164DROP TABLE
159165
160166Drops a table from the database.
161167
162168Syntax:
163169
164-`DROP TABLE tablename`
170+```text
171+DROP TABLE tablename
172+```
165173
166174Syntax:
167175
168-`DROP TABLE users`
176+```text
177+DROP TABLE users
178+```
169179
170180Notes
171181
172182Use with care, because it deletes a file from hard disk.
173183
174184ALTER TABLE
175185
176186Allows you to alter the structure of a table.
177187
178188Syntax:
179189
180-`ALTER TABLE ADD COLUMN columnname`\
181-`ALTER TABLE DROP COLUMN columnname`
190+```text
191+ALTER TABLE ADD COLUMN columnname
192+ALTER TABLE DROP COLUMN columnname
193+```
182194
183195You can only add or drop one column at the time.
184196
185197B\) Data Manipulation Language
186198
187199SELECT FROM
188200
189201Allows you to select data from one or two tables.
190202
191203Syntax:
192204
193-` SELECT fieldlist FROM tablename`\
194-` SELECT fieldlist FROM tablename WHERE condition`\
195-` SELECT fieldlist FROM tablename1 [alias1], tablenameN [aliasN]`\
196-` SELECT fieldlist FROM tablename1 [alias1], tablenameN [aliasN] WHERE condition`
205+```text
206+ SELECT fieldlist FROM tablename
207+ SELECT fieldlist FROM tablename WHERE condition
208+ SELECT fieldlist FROM tablename1 [alias1], tablenameN [aliasN]
209+ SELECT fieldlist FROM tablename1 [alias1], tablenameN [aliasN] WHERE condition
210+```
197211
198212fieldlist can be * for selecting all fields or field1\[,fieldN\]
199213
200214field: fieldname \[AS fieldalias\]
201215
202216condition: see the WHERE topic.
203217
204218Notes
205219
206220When you join **two or more tables** [[you must]] use **fully qualified field names**: tablename.fieldname in the WHERE clause. Both tablenames and fieldnames can be aliased.
207221
208-`SELECT u.userid as mio, u.username as ma, p.productname as muu`\
209-`FROM users u,products p`\
210-`WHERE u.productid=p.productid`
222+```text
223+SELECT u.userid as mio, u.username as ma, p.productname as muu
224+FROM users u,products p
225+WHERE u.productid=p.productid
226+```
211227
212228Using a table alias can save you typing.
213229
214-`   select products.productname as product,count(users.userid) as quantity`\
215-`   from users,products`\
216-`   where users.productid=products.productid`\
217-`   group by product`\
218-`   having quantity>10`\
219-`   order by product desc`\
230+```text
231+ select products.productname as product,count(users.userid) as quantity
232+ from users,products
233+ where users.productid=products.productid
234+ group by product
235+ having quantity>10
236+ order by product desc
237+```
220238
221239The example above shows you that in the WHERE clause you refer to source tables (e.g. products.productid) where as in the GROUP BY, HAVING and ORDER BY clause, you refer to the result table.
222240
223241Always use an aliased field name when using an aggregate function:
224242
225-`count(users.userid) as quantity`\
243+```text
244+count(users.userid) as quantity
245+```
226246
227247WHERE
228248
229249The WHERE clause can be used together with the SELECT, UPDATE and DELETE clauses.
230250
231251Syntax:
232252
233-`WHERE condition`\
253+```text
254+WHERE condition
255+```
234256
235257condition:
236258
237259The condition is an expression that must evaluate to a boolean true or false. The following operators are allowed:
238260
239261Arithmetic:
240262
241263\+ - * / ( )
242264
243265Logic:
244266
245267and, or
246268
247269comparison: \< \<= = \> \>=
248270
249271string constants: e.g. 'Jan Verhoeven'
250272
251273numeric constans: e.g. 12.45
252274
253275fieldnames e.g. userid, users.userid
254276
255277*IMPORTANT NOTE: Sometimes JanSQL engine can't process WHERE clause if there are several conditions and joins. In that case application will freeze. Therefore, try to simplify WHERE clause of the main expression by filtering one of the joined tables prior the main expression. Split the main query into few steps (use subqueries!). This means you have to split the main expression into, for example, two expressions and assign the first one to a variable (ASSIGN TO) that you will use instead of the original table.*
256278
257279IN
258280
259281e.g.
260282
261-`   userid IN (300,401,402)`\
262-`   username IN ('Verhoeven','Smith')`
283+```text
284+ userid IN (300,401,402)
285+ username IN ('Verhoeven','Smith')
286+```
263287
264288LIKE
265289
266290e.g.
267291
268-`    username Like '%Verhoeven'`
292+```text
293+ username Like '%Verhoeven'
294+```
269295
270296You can use the % character as a placeholder to match any series of characters:
271297
272-`    '%Verhoeven' will match Verhoeven at the end of username`\
273-`   'Verhoeven%' will match Verhoeven at the beginning of username`\
274-`    '%Verhoeven%' will match Verhoeven anywhere in username`\
275-` `
298+``` pascal
299+ '%Verhoeven' will match Verhoeven at the end of username
300+ 'Verhoeven%' will match Verhoeven at the beginning of username
301+ '%Verhoeven%' will match Verhoeven anywhere in username
302+```
276303
277304Sub queries
278305
279306You can use a subquery after the IN clause. Only non-correlated sub queries are allowed at the moment. A sub query must select a single field from a table. A sub query is executed at parsing time and returns a comma seperated list of values that replaces the query text in the IN clause. A sub query must be enclosed by brackets. Example: select * from users where productid in (select product id from products where productname like 'Ico%')
280307
281308Notes When using a SELECT with a join between 2 tables [[you must]] use **fully qualified names** (tablename.fieldname) in every part of the query. In all other cases (UPDATE, INSERT) [[you must]] use the **short form fieldname without the tablename**. Repeat it once again: if more than one table joined in sql query, you must use tablename.fieldname; if only one table in a query, you must use fieldname without table name (only fieldname).
282309
283310GROUP BY
284311
285312Allows you to group data according grouping fields. Syntax:
286313
287-`   group by fieldlist`
314+```text
315+ group by fieldlist
316+```
288317
289318fieldlist is a comma seperated list of one or more fields that you want to grouping to be applied. Example:
290319
291-`   select count(userid), username, productid`\
292-`   from users`\
293-`   group by productid`\
294-`   order by productid`\
320+```text
321+ select count(userid), username, productid
322+ from users
323+ group by productid
324+ order by productid
325+```
295326
296327Aggregate functions
297328
298329You can apply the count, sum, avg, max, min, stddev function to an input field. When you use these functions without a GROUP BY clause, the resultset will contain only one row.
299330
300331HAVING
301332
302333Allows you to filter a recordset resulting from a GROUP BY clause. Syntax:
303334
304-`   HAVING expression `
335+```text
336+ HAVING expression
337+```
305338
306339Example:
307340
308-`   select count(userid), username, productid`\
309-`   from users`\
310-`   group by productid`\
311-`   having userid>10`\
312-`   order by productid`\
341+```text
342+ select count(userid), username, productid
343+ from users
344+ group by productid
345+ having userid>10
346+ order by productid
347+```
313348
314349Notes
315350
316351Experienced SQL users will notice that janSQL uses a non-standard syntax in the HAVING clause. Instead of the standard having count(userid)\>10, in janSQL you just use the name of the base table field, in this case userid.
317352
318353You should be aware of the difference between the WHERE clause and the HAVING clause. The WHERE clause is applied to table(s) in the FROM clause. The HAVING is applied after filtering with where and grouping with group by have been applied. The same applies to the ORDER BY clause which is also applied to the final result set.
319354
320355ORDER BY
321356
322357Allows you to sort the resulting recordsets. Syntax:
323358
324-`   ORDER BY orderlist`
359+```text
360+ ORDER BY orderlist
361+```
325362
326363Example:
327364
328-`   select * from users order by #userid asc, productid desc  `
365+```text
366+ select * from users order by #userid asc, productid desc
367+```
329368
330369orderlist is a comma seperated list of one or more order by components: component1\[,componentN\] ordercomponent: \[#\]fieldname \[ASC\|DESC\]
331370
332371By placing the optional **\#** before a fieldname it will be treated as a numeric field in the sort. Remember that in janSQL all data is stored as text. After the fieldname you can optionally put ASC for an ascending sort, or DESC for a descending sort. When you omit the sort direction the default ascending sort order is used.
333372
334373**ASSIGN TO**
335374
336375Allows you to assign the result of a SELECT statement to a named recordset that can be referred to in subsequent statements. This is a non-standard SQL statement. ASSIGN TO is like a **variable assignment**. You can create very complex **compound queries** with ASSIGN TO.
337376
338377Syntax:
339378
340-`   ASSIGN TO tablename selectstatement`
379+```text
380+ ASSIGN TO tablename selectstatement
381+```
341382
342383Example:
343384
344-`   ASSIGN TO mis SELECT userid, username FROM users`
385+```text
386+ ASSIGN TO mis SELECT userid, username FROM users
387+```
345388
346389If tablename allready exists in the catalog then an error occurs. When tablename does not exist in the catalog but was allready assigned to then the existing recordset is overwritten.
347390
348391Notes Make sure that you use output field alias names when you ASSIGN TO using a SELECT with joined tables.
349392
350393When you execute the ASSIGN TO the given name will be assigned to the new recordset and the recordset itself will not be released until you use RELEASE TABLE.
351394
352395RELEASE TABLE
353396
354397Allows you to release any open table from memory, including intermediate tables created with ASIGN TO. This is a non-standard SQL statement. Syntax:
355398
356-`   RELEASE TABLE tablename`
399+```text
400+ RELEASE TABLE tablename
401+```
357402
358403Example:
359404
360-`   ASSIGN TO mis SELECT * FROM users`\
361-`   RELEASE TABLE mis`
405+```text
406+ ASSIGN TO mis SELECT * FROM users
407+ RELEASE TABLE mis
408+```
362409
363410SAVE TABLE
364411
365412Allows you to save any open table, including intermediate tables, to a file. This is a non-standard SQL statement. Syntax:
366413
367-`   SAVE TABLE tablename`
414+```text
415+ SAVE TABLE tablename
416+```
368417
369418When tablename is not open, an error occurs. When you save an intermediate table (created with ASSIGN TO), the intermediate table becomes a persistant table that is also saved with the **COMMIT statement**.
370419
371420Example: ASSIGN TO mis SELECT * FROM users
372421
373-`   SAVE TABLE mis`
422+```text
423+ SAVE TABLE mis
424+```
374425
375426Notes Once you have saved an intermediate table with TABLE SAVE you can not ASSIGN TO anymore.
376427
377428INSERT INTO
378429
379430Allows you to insert data in a table, either row by row or from a recordset resulting from a SELECT. Syntax:
380431
381-`    INSERT INTO tablename [(column1[,column])] VALUES (field1[,fieldN])`\
382-`    INSERT INTO tablename selectstatement`
432+```text
433+ INSERT INTO tablename [(column1[,column])] VALUES (field1[,fieldN])
434+ INSERT INTO tablename selectstatement
435+```
383436
384437Example:
385438
386-`    INSERT INTO users VALUES (600,'user-600');`\
387-`    INSERT INTO users (userid,username) VALUES (601,'user-601');`\
388-`    INSERT INTO users SELECT * FROM users WHERE userid>400`
439+```text
440+ INSERT INTO users VALUES (600,'user-600');
441+ INSERT INTO users (userid,username) VALUES (601,'user-601');
442+ INSERT INTO users SELECT * FROM users WHERE userid>400
443+```
389444
390445Notes When you insert records using a sub select you must make sure that the output fields of the sub select match the fieldnames of tablename. Only values of matching field will be inserted.
391446
392447UPDATE
393448
394449Allows you to update existing data. Syntax:
395450
396-`   UPDATE tablename SET updatelist [WHERE condition]`
451+```text
452+ UPDATE tablename SET updatelist [WHERE condition]
453+```
397454
398455updatelist: field1=value1\[,fieldN=valueN\]
399456
400457condition: see WHERE for the optional condition
401458
402459DELETE FROM
403460
404461Allows you to delete data. Syntax:
405462
406-`   DELETE FROM tablename WHERE condition`
463+```text
464+ DELETE FROM tablename WHERE condition
465+```
407466
408467condition: see WHERE clause for the condition.
409468
410469**C) Functions**
411470
412471In janSQL you can use functions wherever you can use an expression to be calculated (Calculated output fields, WHERE clause, HAVING clause).
413472
414473Use **extra brackets** around function parameters when you have a function with more than one parameter:
415474
416-` SELECT trunc((userid/7),2) as foo FROM users`\
475+```text
476+ SELECT trunc((userid/7),2) as foo FROM users
477+```
417478
418479and not:
419480
420-` SELECT trunc(userid/7,2) as foo FROM users`
481+```text
482+ SELECT trunc(userid/7,2) as foo FROM users
483+```
421484
422485Conversion
423486
424487**fix(expression,precision)**
425488
426489Returns the string presentation of (numeric) expression with precision number of decimals.
427490
428-` select fix((userid/7), 2) as bobo from users order by bobo`\
491+```text
492+ select fix((userid/7), 2) as bobo from users order by bobo
493+```
429494
430495You can also use TRUNC i.s.o. FIX.
431496
432497**asnumber(expression)**
433498
434499Returns (number or string) expression as number. If expression is not a valid floating point number then the function returns 0.
435500
436501**FORMAT function**
437502
438503Formats a integer or floating point value to a string in a way specified by a format string. Syntax:
439504
440-`   format(value,formatstring) `
505+```text
506+ format(value,formatstring)
507+```
441508
442509Example:
443510
444-`   update users set userid=format(userid,'%.8d')`
511+```text
512+ update users set userid=format(userid,'%.8d')
513+```
445514
446515Format strings have the following form: **\[literalstring\]"%" \[width\] \["." prec\] type**
447516
448517• An optional literal string that is copied to the output • An optional width specifier, \[width\] • An optional precision specifier, \["." prec\] • The conversion type character, type
449518
450519The following table summarizes the possible values for type:
451520
452521**d**
453522
454523Decimal. The argument must be an integer value. The value is converted to a string of decimal digits. If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has less digits, the resulting string is left-padded with zeros.
455524
456525**u**
457526
458527Unsigned decimal. Similar to 'd' but no sign is output.
459528
460529**e**
461530
462531Scientific. The argument must be a floating-point value. The value is converted to a string of the form "-d.ddd...E+ddd". The resulting string starts with a minus sign if the number is negative. One digit always precedes the decimal point.The total number of digits in the resulting string (including the one before the decimal point) is given by the precision specifier in the format string—a default precision of 15 is assumed if no precision specifier is present. The "E" exponent character in the resulting string is always followed by a plus or minus sign and at least three digits.
463532
464533**f**
465534
466535Fixed. The argument must be a floating-point value. The value is converted to a string of the form "-ddd.ddd...". The resulting string starts with a minus sign if the number is negative.The number of digits after the decimal point is given by the precision specifier in the format string—a default of 2 decimal digits is assumed if no precision specifier is present.
467536
468537**g**
469538
470539General. The argument must be a floating-point value. The value is converted to the shortest possible decimal string using fixed or scientific format. The number of significant digits in the resulting string is given by the precision specifier in the format string—a default precision of 15 is assumed if no precision specifier is present.Trailing zeros are removed from the resulting string, and a decimal point appears only if necessary. The resulting string uses fixed point format if the number of digits to the left of the decimal point in the value is less than or equal to the specified precision, and if the value is greater than or equal to 0.00001. Otherwise the resulting string uses scientific format.
471540
472541**n**
473542
474543Number. The argument must be a floating-point value. The value is converted to a string of the form "-d,ddd,ddd.ddd...". The "n" format corresponds to the "f" format, except that the resulting string contains thousand separators.
475544
476545**m**
477546
478547Money. The argument must be a floating-point value. The value is converted to a string that represents a currency amount. The conversion is controlled by the CurrencyString, CurrencyFormat, NegCurrFormat, ThousandSeparator, DecimalSeparator, and CurrencyDecimals global variables, all of which are initialized from the Currency Format in the International section of the Windows Control Panel. If the format string contains a precision specifier, it overrides the value given by the CurrencyDecimals global variable.
479548
480549**s**
481550
482551String. The argument must be a string value. The string is inserted in place of the format specifier. The precision specifier, if present in the format string, specifies the maximum length of the resulting string. If the argument is a string that is longer than this maximum, the string is truncated.
483552
484553**x**
485554
486555Hexadecimal. The argument must be an integer value. The value is converted to a string of hexadecimal digits. If the format string contains a precision specifier, it indicates that the resulting string must contain at least the specified number of digits; if the value has fewer digits, the resulting string is left-padded with zeros.
487556
488-**`Date functions`**` `
557+```text
558+Date functions
559+```
489560
490561Several date functions make working with date strings easier.
491562
492563YEAR
493564
494565Extracts the integer year part of a yyyy-mm-dd date string.
495566
496567MONTH
497568
498569Extracts the integer month part of a yyyy-mm-dd date string.
499570
500571DAY
501572
502573Extracts the integer day part of a yyyy-mm-dd date string.
503574
504575WEEKNUMBER
505576
506577Returns the integer weeknumber of a yyyy-mm-dd date string.
507578
508579EASTER
509580
510581Returns the easter yyyy-mm-dd date string of a given integer year.
511582
512583DATEADD
513584
514585Adds a given number of time intervals to a given data and returns the resulting data as a yyyy-mm-dd data string. Syntax:
515586
516-`    DATEADD(interval,number,datestring)`\
587+```text
588+ DATEADD(interval,number,datestring)
589+```
517590
518591Interval can be: 'd' (day), 'm' (month), 'y' (year), 'w' (week), 'q' (quarter). Number must be an integer number. datestring must be in the yyyy-mm-dd format.
519592
520-**`String Functions`**` `
593+```text
594+String Functions
595+```
521596
522597janSQL comes with a range of functions that work on strings.
523598
524599**soundex(expression)** Calculates the soundex value of (string) expression. Only usefull with english terms.
525600
526601**lower(expression)** Converts (string) expression to lower case.
527602
528603**upper(expression)** Converts (string) expression to upper case.
529604
530605**trim(expression)** Trims (string) expression from leading and trailing spaces.
531606
532607**left(expression,count)** Returns the first count characters of expression
533608
534609**right(expression,count)** Returns the last count characters of expression
535610
536611**mid(expression,from,count)** Returns count characters of expression starting at from.
537612
538613**length(expression)** Returns the length of (string) expression. Can be used to e.g. select fields that exceed a given length.
539614
540615**replace(source,oldpattern,newpattern)** Replaces oldpattern with new pattern in the source string. Is case-insensitive.
541616
542-`   UPDATE users SET username=replace(username,'user-','foo-')`\
617+```text
618+ UPDATE users SET username=replace(username,'user-','foo-')
619+```
543620
544621**substr_after(source,substring)** Returns the part of source that comes after substring. If substring is not found an empty string is returned.
545622
546623**substr_before(source,substring)** Returns the part of source that comes before substring. If substring is not found an empty string is returned.
547624
548-**`Numeric Functions`**` `
625+```text
626+Numeric Functions
627+```
549628
550629Numeric functions work on strings as if they were numbers. Although janSQL is based on strings you can still enter values like 1234, which can be treated like numbers.
551630
552631sqr(expression) Calculates the square of (numeric) expression.
553632
554633sqrt(expression) Calculates the square root of (numeric) expression.
555634
556635sin(expression) Calculates the sin of (numeric) expression.
557636
558637cos(expression) Calculates the cos of (numeric) expression.
559638
560639ceil(expression) Returns the lowest integer greater than or equal to (numeric) expression.
561640
562641floor(expression) Returns the the highest integer less than or equal to (numeric) expression.
563642
564643# Dependencies / System Requirements
565644
566645- None
567646
568647Status: *Alpha*
569648
570649# Open issues/improvement ideas
571650
572651Below is a list of open issues (or bugs, if you want) and improvement ideas. If you have any patches/fixes for the code (not limited to these issues), please let use know via the ZMSQL thread on the forum: [1](http://lazarus.freepascal.org/index.php/topic,13821.0.html) Of course, ZMSQL is part of the Lazarus CCR repository, so you can post bug reports/patches on Mantis using the CCR category.
573652
5746531\. TBufDataset bug Currently TBufDataSet (ancestor of TZMQueryDataSet) has a bug (http://bugs.freepascal.org/view.php?id=19631 is solved!) that causes Refresh method to delete all records
575654
5766552\. Slow query execution in JanSQL Extremely slow query execution when more than one table joined in query when there is an additional where clause in the query. It can be overcome with the "ASSIGN TO variable" non-standard expression First execute query on a table with where clasue, assign resultset to a variable and then use the variable in a second query (instead of the table).
577656
578657Thus, instead of: "SELECT ordrs.ordr AS order, ordrs.ordr_type AS order type,ordrs.prdct AS product,ordrs.prdct_dscr AS product description,ordrs.prdct_targ_qty AS order quantity,ordrs.prdct_targ_qty_unt AS order unit,rqrmts.cmpnt AS component,rqrmts.cmpnt_dscr AS component description,rqrmts.cmpnt_rqrd AS required quantity of component FROM ordrs,rqrmts WHERE ordrs.ordr=rqrmts.ordr AND ordrs.prdct=10010356;", use this non-standard SQL expression: "ASSIGN TO temp_ordrs SELECT * from ordrs WHERE prdct=10010356; SELECT temp_ordrs.ordr AS order, temp_ordrs.ordr_type AS order type,temp_ordrs.prdct AS product,temp_ordrs.prdct_dscr AS product description,temp_ordrs.prdct_targ_qty AS order quantity,temp_ordrs.prdct_targ_qty_unt AS order unit,rqrmts.cmpnt AS component,rqrmts.cmpnt_dscr AS component description,rqrmts.cmpnt_rqrd AS required quantity of component FROM temp_ordrs,rqrmts WHERE temp_ordrs.ordr=rqrmts.ordr;"
579658
5806593\. JanSQL has problems with typecasts. It can be tricky to guess how to cast values. Use 'ASNUMBER(some_value) AS something' whenever you do something with numerical values.
581660
5826614\. Parameter support is currently quite limited. Basically, named parameters must be used and they are replaced by its values as literal strings. You must enclose parameter identifiers in SQL string by quotes!
583662
5846635\. Multiline support Investigate setting the sdfdata.AllowMultiline property to true when required to allow CSV data that contains line breaks. See <http://bugs.freepascal.org/view.php?id=17285> Not sure whether JanSQL database engine is able to handle this? The parameters set for SdfDataset in zmsql corresponds to the csv format that JanSQL uses
585664
5866656\. Missing outer (lef and right) joins in SQL queries Absence of outer joins in sql queries siriously limits sql capabilities. It can be partially overcomed by using non-standard 'ASSIGN TO variable' statement, which means that you can create subqueries to be used in further sql statement. However, improving janSQL engine to be able to execute left and righ outer joins should be solved till beta.
587666
588667# Installation
589668
590669- Unpack
591670- Compile
592671
593672You may also need to add **LCLPlatformDef** to the implementation **uses** list of unit QBuilder. ZMSQL uses some constants defined in LCLPlatformDef. At least under Lazarus 1.7 development version.
594673
595674# The Demo Applications
596675
597676**Installation**
598677
599678- Open the applications in TestProject and TestProject1
600679- compile
601680- run
602681
603682# See Also
604683
605684- [[CSV]]
606685- [[JCSV (Jans CSV Components)]]
607686
608687# Change Log
609688
610689For more details, see zmquerydataset.pas
611690
612691Current version 0.1.20: 19.08.2017\
613692ZMSQL version 0.1.20, 19.08.2017: various improvements by Edgar Fernando Rodriguez Pacheco (edgarrod71@gmail.com)
614693
615694ZMSQL version 0.1.19, 08.02.2015: by Zlatko Matić
616695
617696- New component TZMQueryBuilder, based on Open QBuilder Engine, is added to the zmsql package.
618697
619698TZMQueryBuilder uses TOQBEngineZmsql, which is TOQBEngine descendant. TOQBEngineZmsql is in based on code of the Open QBuilder Engine for SQLDB Sources created by Reinier Olislagers, modified and adapted for the ZMSQL by Zlatko Matić. It incorporates QBuilder visual query builder(Copyright (c) 1996-2003 Sergey Orlik , Copyright (c) 2003 Fast Reports, Inc.)
620699
621700- Added procedure TZMConnection.GetTableNames(FileList: TStrings);
622701- Added procedure TZMQueryDataSet.LoadTableSchema;
623702
624703ZMSQL version 0.1.18, 10.04.2014: by Zlatko Matić
625704
626705- Bugfix release. There was funny bug in zmquerydataset destroy method - dataset would be saved prior destroying if persistent save was enebaled.
627706
628707This was wrong, causing saving CSV file copy in wrong directory.
629708
630709ZMSQL version 0.1.17, 07.03.2014: by Mario Ferrari
631710
632711- Error situations that used ShowMessage now raise a generic exception containing the message itself. Only one ShowMessage remains for a design-time case.
633712
634713ZMSQL version 0.1.16, 28.01.2014: by Zlatko Matić
635714
636715- Internal optimizations and bugfixes.
637716- Creation of JanSQL instances moved from ZMConnection to ZMQueryDataset, in order that ZMQueryDataset can be used in multithreaded applications.
638717- New properties (ReferentialUpdateFired, ReferentialDeleteFired, ReferentialInsertFired) that tells that a referential action is in progress.
639718
640719ZMSQL version 0.1.15, 28.01.2014: by Zlatko Matić
641720
642721- Internal optimizations and bugfixes.
643722- Autoincrement fields (ftAutoInc) are now working.
644723- Improved visibility of TDataset methods and properties.
645724- ZMQueryDataset now works with TBufDataset as ancestor (as in CodeTyphon v.4.70). ZMBufDataset upgraded to the current TBufDataset in CodeTyphon v. 4.70.
646725- Added property MasterDetailFilter: Boolean which switches master/detail filtration on/off.
647726- Removed property DecimalSeparator. ZMSQL now use system settings for decimal and thousand separator.
648727- ZMQueryDataset can handle float value even if thousand separator is present (in a .csv file).
649728- Better handling locale settings and conversion from ANSI to UTF8.
650729- Persistent fields are working now.
651730
652731(Solved by a trick: persistent fields loaded from .lfm are recreated, propertie from old fields are copied to new fields and old fielsa are deleted.
653732
654733Current version 0.1.14: 01 January 2014\
655734ZMSQL version 0.1.14, 01.01.2014: by Zlatko Matić
656735
657736- Internal optimizations.
658737- Based on TZMBufDataset instead TBufDataset, because problems with current TBufDataset version.
659738- ZMQueryDataset now loads from and saves to files with .csv extension, instead of .txt extension.
660739- Added ManageFields method, which decides what to do with Fields and FieldDefs.
661740- Reworked InspectFields procedure, better deduction of FieldDefs and Fields status.
662741- Enabled automatic creation of persistent fields objects from predefined fielddefs.
663742- New published properties: DynamicFieldsCreated, PeristentFieldsCreated, MemoryDataSetOpened,
664743- New public methods: CreateDynamicFieldsFromFieldDefs, CreatePersistentFieldsFromFieldDefs;
665744- Added "\$DEFINE ZMBufDataset" compiler directive.
666745
667746ZMSQL version 0.1.13, 13.01.2013: by Zlatko Matić
668747
669748- Few bug fixes.
670749- TZMbufdataset replaced with current TBufDataset as ancestor. Tested with current FPC 2.7.1 in CodeTyphon v. 3.10.
671750
672751If this does not work for your FPC version, then replace TBufDataSet with TZMBufDataset as ancestor. The TZMBufDataset will stay present latent inside the package, just in case that further development od TBufDataSet goes in direction incompatible with zmsql.
673752
674753- Added procedure InternalRefresh;override;
675754
676755TBufDataSet's InternalRefresh does troubles, so it is overriden to do nothing. It seems that all functionalities which ZMQueryDataset needs are implemented inside TDataSet's Refresh method and that InternalRefresh is not needed at all.
677756
678757ZMSQL version 0.1.12, 12.02.2012
679758
680759- Critical bug in DoBeforeDelete solved: The bug was causing referential deletion of all records, even those not related.
681760- Few enhancements regarding persistent save functionality.
682761
683762ZMSQL version 0.1.11, 05.02.2012
684763
685764- DoAfterScroll call added to DoFilterRecord,in order to referesh detail dataset after filtering master dataset.
686765- FormatSettings.QuoteStrings:=\[qsAlways\] added in SaveToCSV method, so that strings are saved enclosed in double guotes.
687766- FloatDisplayFormat property added to ZMConnection. If set, it will be applied to all connected zmquerydatasets and override TFloatField's settings defined in zmquerydatasets.
688767- SetFloatDisplayFormat method added. This method takes formatting from FloatDisplayFormat property of ZMConnection, if set. Call to SetFloatDisplayFormat added in FieldsFromScratch and FieldsFromFieldDefs.
689768- Since in Jansql DecimalSeparator:=SysUtils.DefaultFormatSettings.DecimalSeparator has been added, so that jansql takes-over system decimal separator, the same is added to SaveToCSV method. It means that now zmquerydataset executes queries, loads data from CSV and saves dataset to csv using system settings for decimal separator. System settings can be, however, overriden by changing values of ZMConnection's properties DecimalSeparator and FloatDisplayFormat.
690769- ZMFieldsFromFieldDefs renamed to FieldsFromFieldDefs; ZMFieldsFromScratch renamed to FieldsFromScratch.
691770
692771ZMSQL version 0.1.10, 20 January 2012
693772
694773- procedure CopyFromDataset rewritten in way that now it uses ZMFieldsFromScratch and ZMFieldFromFieldDefs methods for dynamical fields creation.
695774
696775In case of previously defined fielddefs, they will be used, otherwise, fielddefs from a dataset will be copied to ZMQueryDataset.
697776
698777- FSourceData expanded to sdOtherDataset. FOtherDatasetImport added.
699778
700779ZMSQL version 0.1.9, 15 January 2012
701780
702781- Bug fixes in DoFilterRecord and SetMasterSource procedures, to enable custom filtration working correctly.
703782- In procedure TZMQueryDataSet.ZMFieldsFromScratch added formula for setting MaxIndexes count.
704783
705784The formula is: MaxIndexesCount:=(2*(self.FieldDefs.Count)+3).This default value includes ascending and descending index on every column, two default TBufDataset indexes and one spare index. The formula is used in cases when LoadFromCSV or QueryExecute is called without prior FiedlDefs definition. You can still set MaxIndexesCount to any value before calling CreateDataset. Note that in zmsql you can use function SortDataset (const pFieldName:String):Boolean that creates indexes on the fly.
706785
707786- Bug fix in EmptyDataset method, so that it delete all records in case of active filter.
708787
709788ZMSQL version 0.1.8, 08 January 2012
710789
711790- Since there was no visible improvement in BufDataSet regarding "Refresh bug" for a very long time, and it seems that TBufDataset is not maintained successfully any more, I have decided to base zmsql on last stable TBufDataset version that performed Refresh method correctly,which appears to be present in fpc 2.2.4.
712791
713792Therefore, new zmbufdataset.pas and zmbufdatasetparser.pp units are now actually downgraded to fpc 2.2.4. This choise will not change anymore and this is starting point for further independent development of zmbufdataset unit as direct ancestor of zmquerydataset. However, we can always come back to TBufDataset as direct ancestor of zmquerydataset (while preserving zmbufdataset as an alternative) if following criteria is met:
714793
715-` 1. DoFilterRecord method is virtual and protected.`\
716-` 2. Refresh method works correctly `
794+```text
795+ 1. DoFilterRecord method is virtual and protected.
796+ 2. Refresh method works correctly
797+```
717798
718799Until then, zmbufdataset remains direct ancestor of zmquerydataset and will fork from TBufDataset development.
719800
720801- Reconnecting of ZMConnection is added in QueryExecute and LoadFromCSV methods, each time data is loaded by query or import from csv.
721802
722803This prevents peculiar inconsistences observed during query execution in some circumstances. This odd behavior of jansql has to be throughly investigated...
723804
724805- In previous versions regular filtering was broken by DoFilterRecord everriding. It is solved now by adding:"if not Acceptable then exit;" after "inherited DoFilterRecord(Acceptable);". this way normal filtering functionality with Filter and Filtered properties is preserved.
725806
726807ZMSQL version 0.1.7, 01 January 2012
727808
728809- FDoReferentialUpdate:Boolean field added to signalize dsEdit state in DoBeforePost, which is then used in DoAfterPost as signal to perform referential update. This solved bug that caused referential update of all records in case of insert.
729810
730811- Added public read-only property OldRecord. This can be useful during run-time.
731812
732813ZMSQL version 0.1.6, 28 December 2011
733814
734815- Referential update logic moved from DoBeforePost to DoAfterPost procedure, in order to solve problems with multilevel referential integrity.
735816
736817- UpdateFOldRecord triggering moved from DoAfterScroll and DoAfterPost to DoBeforeInsert, DoBeforeDelete and DoBeforeEdit.
737818
738819- Inspecting and matching of referential conditions for referential update changed from custom filtering to iteration and inspection for referential conditions for every record of SlaveDataset.
739820
740821- Bugs in PrepareQuery and DoFilterRecord, as well as few other small bugs are solved.
741822
742823- ZMBufDataSet updated with recent bufdataset changes.
743824
744825- ZMBufDataSetParser added to package.
745826
746827- Bug in Disconnect procedure solved.
747828
748829Change commit: 4 September 2011
749830
750831- Added some things to JanSQL tokenizer and expression evaluator. Still needs implementation of those expressions (outer joins, select distinct etc.)
751832
752833Version 0.1.5: 12 August 2011
753834
754835- Two small demo projects are included in the zip. First one demonstrates referential integrity, master/detail filtration, parameterized queries and difference between using predefined FieldDefs and FieldDefs created on the fly. The second one demostrates loading and saving to CSV table.
755836
756837- Improvements: ZMSQL now enables decimal separator to be chosen (new property in TZMConnection) for ftFloat field type. It does not influence default CSV save format, but only data representation.
757838 - Caution: Changing value of a ZMConnection.DecimalSeparator will change SysUtils.DefaultFormatSettings as well, so this will influence on the whole application!
758839- If you leave ZMConnection.DecimalalSeparator empty, default format settings are going to be used
759840- Added overloaded procedure, procedure SaveToCSV (pDecimalSeparator);overload; so that you can save a dataset with custom decimal separator. The regular SaveToCSV uses dot as decimal separator, because JanSQL database engine uses that format.
760841
761842Version 0.1.4: 8 August 2011
762843
763844- Successfully implements REFERENTIAL INTEGRITY!
764845- A simple test project is provided inside the package folder and demostrates new features from zmsql 0.1.3 and 0.1.4:
765846 - queries with joined tables
766847 - master/detail filtration/synchronization
767848 - referential integrity (insert/update/delete)
768849 - parameterized queries
769850
770851Version 0.1.3: 2 August 2011
771852
772853- This version brings master/detail synchronization.
773854- The test project now also demonstrates master/detail synchronization and parameterized queries.
774855
775856Version 0.1.2: 28 July 2011
776857
777858- This version brings initial support for parameterized queries (it borrows TParams collection from SQLDB).
778859- Currently, this support is very basic, parameters must be passed by name (ParamByName) and their values are passed as string literals to SQL string before query execution.
779860- There is a Test project included in the package, where you can see how parameters are used.
780861
781862Version 0.1.1: 26 July 2011
782863
783864- QueryExecute method fixed. SqlText TStrings property must be transformed to String prior to passing it JanSQL engine and spaces must be inserted between Sqltext lines.
784865
785866Version 0.1.0: 13 July 2011
786867
787868---
788869*From the Free Pascal wiki, page "ZMSQL", as it stood on 2023-10-20 after a change by Bart, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
789870Category: Components
790871Category: Databases
791872Category: Lazarus
792873Category: Lazarus-CCR

Back to history