
EN: rebol.com -
rebol.org -
rebol.net -
FR: Rebol Documentation Project -
forum RebelBB -
rebol-france.org -
forum codeur -
Projet de Traduction de la documentation de sql-protocol
Règles de travail:
— Alphé Salas-Schumann 26/10/2005 13:02 — Marco 29/10/2005 19:52
The SQL-PROTOCOL Documentation
Documentation SQL-PROTOCOL
SQL-PROTOCOL is a Relational Database Management System (RDBMS) entirely written in REBOL with JOIN and SORT capability.
SQL-PROTOCOL est un Système de Gestion de Base de Données Relationnel (SGBDR) entièrement écrit en REBOL incluant le JOIN et le SORT
The main goal is to have a light database engine which can be embedded in any REBOL application.
Le but principal est de disposer d’un moteur de base de données léger qui peut être intégré dans n’importe quelle application REBOL.
Moreover, one of the objectives of SQL-PROTOCOL is to be compatible with the ODBC driver {Microsoft text driver (*.csv,*.txt)} in order to provide a quick and simple way to share data between REBOL application and other application like Excel, VB or any ODBC application.
De plus, un des objectifs de SQL-Protocol est d’être compatible avec le pilote ODBC {Microsoft text driver (*.csv,*.txt)} afin de fournir une façon simple et rapide de partager des données entre une application REBOL et d’autres applications comme EXCEL, VB ou n’importe quelle application ODBC.
This quick example illustrates how to load the protocol, open a database, select some rows from two tables, probe the result and close the database.
Ce court exemple montre comment charger en mémoire SQL-PROTOCOL, ouvrir une base de données, lire quelques lignes provenant de deux tables, afficher le résultat et fermer la base de données.
do %sql-protocol.r db: open sql:my-db insert db [SELECT * FROM a b WHERE a.c2 = b.c1 AND a.c1 = 1 ORDER BY 1 [2 DESC] ] foreach item copy db [probe item] close db
NOTA BENE This documentation include what is already realized but also on what I intend to develop. I indicate each time when something in not implemented if it will bo done soon or not.
Cette documentation porte sur SQL-PROTOCOL tel qu’il est mais aussi sur ce que j’essaierai de développer. J’indique à chaque fois lorsqu’une fonctionnalité n’est pas implémentée et si elle le sera dans un proche avenir ou pas.
Query on the database must be done in a REBOL dialect very near to standard SQL query. Les requêtes sur la base de données doivent être faite en utilisant un dialecte REBOL vraiment très proche du langage standard de requêtes SQL.
The engine carries out only the following requests: Le moteur de requête supporte uniquement les requêtes suivantes:
SELECT ... FROM ... WHERE ... ORDER BY ... INSERT ... INTO ... VALUES ... UPDATE ... SET ... WHERE ... DELETE FROM ... WHERE ... CREATE TABLE ... [...] TYPE ... DROP TABLE ...
SQL-PROTOCOL supports 4 table types (format) :
SQL-PROTOCOL supporte 4 formats de table
By default : Par défaut:
SQL-PROTOCOL implements the following queries :
SQL-PROTOCOL implémente les requêtes suivantes:
SELECT which allows you to select rows from table(s).
SELECT qui vous permet de choisir les lignes d’une(des) table(s)
INSERT which allows you to insert row(s) in a table.
INSERT qui vous permet d’insérer une(des) ligne(s) dans une table
UPDATE which allows you to update row(s) in a table.
UPDATE qui vous permet de modifier la(les) ligne(s) dans une table
DELETE which allows you to delete row(s) from a table.
DELETE qui vous permet de suppprimer une(des) lignes d’une table
Opening a database is very simple: L’ouverture de la base de données est vraiement simple
open sql:my-database
In this case, the protocol open the database contained in the directory my-database.
Dans ce cas, le protocol ouvre la base de données contenue dans le dossier my-database
You can specify the standard /new refinement in order to reinitilize the database (this is not implemented up to now but I will make it soon):
Vous pouvez spécifier le rafinement standard /new afin de réinitilizer la base de données (ceci n’est pas encore implémenté à ce jour mais le serra très prochainemen):
open/new sql-my-database
In this case, all the file contained in the directory are erased and a new schema.ctl file is created. Dans ce cas, tout les fichier contenus dans le dossier sont effacés et un nouveau fichier schéma.ctl est créé.
Other refinement will cause an error (error are not thrown up to now but I will change it soon).
L’utilisation d’autres raffinements causeront une erreur (les erreures ne sont pas retournées mais je corrigerai ça prochainement)
When you open a database, you can also precise the file name of the schema :
Quand vous ouvrez une base de données vous pouvez aussi préciser le nom du fichier de schéma :
open sql:my-database/my-schema.txt
In this case, if the schema file does’nt exist, it is created. It’s the same with the directory and the /new refinement is also authorized.
Dans ce cas, si le fichier de schéma n’existe pas, il est créé. De façon analogue au fonctionnement des dossiers et le raffinement /new est aussi autorisé
The SQL dialect for SELECT is very similar to the SQL To query the database, you have to insert the query block into the port and next to get the result either by a copy, a first or a pick.
Le dialecte SQL pour la focntion SELECT est vraiement similaire à la requette SQL pour intérroger la base de données, vous pouvez inserrer le bloc de requête dans le port et en suite obtenir le résultat soit par un copy, soit par un first ou par un pick.
Quick example: Example simple:
db: open sql:my-db insert db [SELECT * FROM my-table] foreach item copy db [probe item] close db
To select all columns from a table you can use the * :
Pour choisir toutes les colonnes d’une table pouvez utiliser *:
insert db [SELECT * FROM a]
If you want to select some specific columns, you have to use the notation alias.column:
Si vous voulez selectionner quelques colonnes spécifiques, vous devez utiliser la notation alias.colonne:
insert db [SELECT a.c1 a.c2 FROM a]
The same notation is mandatory in the WHERE clause :
La même notation est obligatoire dans une clause WHERE:
insert de [SELECT * FROM a WHERE a.c1 = 2]
You can also give an alias name to a table. In this case, you have to set the table / alias pair into a block :
Vous pouvez aussi donner un nom d’alias a une table. Dans ce cas vous devez fournir la paire table / alias dans un bloc:
insert db [SELECT t1.c1 t1.c2 FROM [a t1]]
Nota Bene Remember, it’s a dialect so you have to respect REBOL syntax and don’t forget to place a space before an after the = or all other operator (+, -*, /, >, <, ).
Rappel, c’est un dialecte donc vous devez respecter la syntaxe REBOL et ne pas oublier de placer un espace avant et après le = ou tout autre opérateur (+, -, *, /, >, <, ).
To do a join, you do simply :
Pour faire un JOIN, faire simplement:
insert db [SELECT * from a b]
If you want only some columns, you have to give the list (always with the notation alias.column) :
Si vous voulez uniquement quelques colonnes, vous devez fournir une liste (toujours aves la notation alias.colonne) :
insert db [SELECT a.c1 a.c2 b.c1 FROM a b WHERE a.c1 = b.c2]
If you want select some columns from a table and all from another, you can use the alias.* notation :
Si vous voulez choisir quelques colonnes depuis une table et toutes c’est d’une autre table, vous pouvez utiliser la notation alias.* :
insert db [SELECT a.c1 b.* FROM a b]
When you join a table with itself, you have to give an alias for each table :
Quand vous réaliser la jointure d’une table avec elle même, vous devez fournir un alias pour chacune des tables :
insert db [SELECT t1.c1 t2.c1 FORM [a t1] [a t2] WHERE t1.c1 = t2.c2]
Nota Bene Remember, it’s a dialect so you have to respect REBOL syntax and don’t forget to place a space before an after the = or all other operator (+, -*, /, >, <, ).
Rappel, c’est un dialecte donc vous devez respecter la syntaxe REBOL et ne pas oublier de placer un espace avant et après le = ou tout autre opérateur (+, -, *, /, >, <, ).
You can give an ORDER BY clause in order to sort the result.
Vous pouvez fournir une clause ORDER BY afin de trier le résultat.
You can either give the column(s) number
Vous pouvez fournir les indices des colonnes
insert db [SELECT * FROM a ORDER BY 1 2 3]
Or you can give the columns name by its alias.columns name :
Ou vous pouvez fournier une colonne désignée par son nom alias.colonne :
insert db [SELECT * FROM a ORDER BY a.c1 a.c2 a.c3]
By default, the engine sort the result in ascending order, but you can sort it in descending order by giving the pair alias.columns ASC or DESC in a block :
Par défaut, le moteur tri de le résultat par ordre croissant, mais vous pouvez le trier dans l’ordre décroissant en fournissant la paires alias.colonnes ASC ou DESC dans un bloc :
insert db [SELECT * FROM a ORDER BY [a.c1 ASC] [a.c2 DESC]]
ASC or DESC can also be given with columns index :
ASC ou DESC peuvent aussi être donné avec les indices des colonnes :
insert db [SELECT * FROM a ORDER BY [1 ASC] 2 [DESC]]
Nota Bene Remember that GROUP BY, HAVING and statistical function (COUNT(…), MAX(…), etc…) are not implemented. It’s the same for LIKE and IN word.
Rappel, GROUP BY, HAVING et les fonctions statistiques (COUNT(…), MAX(…), etc…) ne sont pas implémentées. Il en va de même pour les mots LIKE et IN.
For INSERT, the dialect is quite simple.
Pour INSERT, le dialecte est vraiement simple.
Quick example:
Example rapide:
insert db [INSERT INTO a VALUES [1 2 3]]
When you insert a row in a table, you must give a value for all columns otherwise, they are set to none (NULL).
Quand vous insérer une ligne dans une table, vous devez fournir une valeur pour toutes les colonnes autrement, elles sont configurées à none (NUL).
When you give the columns list, you must give all the columns otherwise the mussing columns are set to none (NULL).
Quand vous donner une liste de colonne, vous devez fournir toutes les colonnes autrement la colonne manquante est configurée à none (NUL).
The value are inserted in the table columns order even if the columns are in another order in the columns list.
La valeur est insérée dans l’ordre des colonnes d’une table même si les colonnes sont dans un ordre différent dans le liste des colonnes
You can give many rows after the VALUES clause just by giving many rows (one block of value for each rows)
Vous pouvez fournir plusieurs lignes après la clause VALUES juste en donnant plusieurs lignes (un bloc de valeurs pour chaque lignes)
You can also insert rows with values selected from another query (not implemented now)
Vous pouvez aussi insérer des lignes avec des valeurs choisies à partir d’une autre requete (pas implémenté actuellement)
Inserting one row without specifying the column list :
insert db [INSERT INTO a VALUES [1 2 3]]
Inserting one row with a column list :
insert db [INSERT [c b a] INTO a VALUES [3 2 1]]
Inserting many rows at a time :
insert db [INSERT INTO a VALUES [1 2 3] [2 3 4] [3 4 5]]
Inserting rows selected from another query (this is not implemented but it will be soon because it’s easy to make) :
insert db [INSERT INTO temp SELECT * FORM a b WHERE a.c2 = b.c1 ORDER BY a.c1 b.c1]
For UPDATE, the dialect is also very similar to SQL.
Quick example :
insert db [UPDATE a SET c2: 3 WHERE c1 = 1]
You can update only one table at a time. If the WHERE clause correspond to many rows, all the corresponding rows are updated The where clause is optional. If WHERE is ommited, all the row of the table are updated.
Nota Bene You must use the simple column notation, not the alias.columnnotation
If you want, you can set many columns at a time :
insert db [UPDATE a SET c2: 3 c3: 4 WHERE c1: 1]
Nota Bene Remember, it’s a dialect so you have to respect REBOL syntax and don’t forget to place a space before an after the = or all other operator (+, -*, /, >, <, ).
For DELETE, it’s very simple.
Quick example :
insert db [DELETE FROM a WHERE c1 = 1]
Nota Bene You must use the simple column notation, not the alias.columnnotation
Deleting all rows in a table :
insert db [ DELETE FROM a ]
SQL-PROTOCOL implements the following DDL (Data Definition Language) queries:
For CREATE TABLE the dialect is extended in order to have a better control on the file creation.
Quick example .
insert db [CREATE TABLE a [c1 c2 c3]]
Creating a table without column type :
insert db [ CREATE-TABLE table-name [C1 C2 C3] ]
As REBOL is an untyped programming language, it’s more simple to ommit the columns type for DATA or HEAP protocol.
Creating a DATA or HEAP table with full columns description (this is not implement up to now and I will make later) :
insert db [ CREATE TABLE a [ [F01 binary!] [F02 bitset!] [F03 block!] [F04 char!] [F05 datatype!] [F06 date!] [F07 decimal!] [F08 email!] [F10 file!] [F11 get-word!] [F12 hash!] [F13 hex!] [F14 image!] [F15 integer!] [F16 issue!] [F17 list!] [F18 lit-path!] [F19 lit-word!] [F20 logic!] [F21 money!] [F22 pair!] [F23 paren!] [F24 path!] [F25 refinement] [F26 set-path] [F27 set-word] [F28 string] [F29 tag] [F30 time] [F31 tuple] [F32 url] [F33 word] ] TYPE = HEAP ]
You can create a CSV table without giving the columns type and length. In this case, you can put what you want in each row but this is not supported by {Microsoft text driver).
insert db [ CREATE TABLE a [C1 C2 C3] type = CSV]
By default CSV table include the header, the format is Delimited and use semicolumn delimiter (;).
Creating a CSV table with full columns description. By default CSV table include the header, the format is Delimited and use semicolumn delimiter (;).
insert db [ CREATE TABLE a [ [F01 Bit] [F02 Byte] [F03 Char Width 255] [F04 Currency] [F05 Date] [F06 Float] [F07 Integer] [F08 LongChar] [F09 Short] [F10 Single] ] TYPE = CSV ]
Creating a CSV table with full columns description and specific table type
insert db [ CREATE TABLE a [ [C1 Integer] [C2 Char 255] [C3 Date] ] TYPE = [ CSV ColNameHeader: false format: CSVDelimited ] ]
Nota Bene TYPE [….] is still not implemented, only TYPE CSV is allowed
Creating a FIXED table with full columns description
insert db [ CREATE TABLE a [ [F01 Bit 1] [F02 Byte 3] [F03 Char 255] [F04 Currency 15] [F05 Date 6] [F06 Float 21] [F07 Integer 11] [F08 LongChar 32] [F09 Short 5] [F10 Single 255] ] TYPE = FIXED ]
You can also precise if the header is saved in the file or not:
insert db [ CREATE TABLE a [ [C1 Integer 11] [C2 Char 255] [C3 Date 6] ] TYPE = [ FIXED ColnameHeader: true ] ]
To drop a table, the dialect is very simple:
insert db [ DROP TABLE table-name ]
If the table doesn’t exist, an error is thrown.
You can if needed use directly the DATA, HEAP, CSV and FIXED protocol. These protocols are named file protocol.
DATA, HEAP, CSV and FIXED protocol are usefull to store and access REBOL datatype block thru protocol.
DATA to store REBOL values as block of values into a file. HEAP to store REBOL values as block of values into memory. CSV to store REBOL value as character separated records. FIXED to store REBOL value as fixed length record.
The advantage is to have with a standard input, output and interface access to many file format. These normalized access simplify file read and write and reduce the debuggind time. It’s allows you to insert, update or delete records as simple as managing blocks.
The usage of file protocol differs form one protocol to the other, only when you open the file. All other access are standized.
To open a DATA or HEAP file, you use the standard open function :
my-file: open DATA:my-datafile.data
If the extension is ommited, the .data exetension is automaticaly added. If the file doesn’t exist, it is created. If you use the /new extension, the file is cleared during the open. When /line and /direct refinement are used an error is thrown.
To open a CSV or FIXED file, you use the standard open function :
my-file: open CSV:my-datafile.data
If the file doesn’t exist, it is created. If you use the /new extension, the file is cleared during the open. When /line and /direct refinement are used an error is thrown. If you want to precise the file structure, you have to make the port before opening it and to give the file schema in a block :
my-file: open make port! [scheme: 'csv schema: [
ColNameHeader: true
format: "Delimited" ; or CSVDelimited or TABDelimited
delimiter: ";" ; or any character except doublequote ("), line feed (^M) and newline (^/)
cols: [
[C1 Char width 10]
[C2 Integer]
]
]
If you don’t give the schema, the CSV protocol detect automaticaly the fileds and their type. By default, char field have a length of 255. For FIXED (FixedLength) file, the schema and field length are mandatory.
To insert data, use the standard insert function :
insert my-file ["data 1" "data 2" 3 4]
If you want to insert many records, you can insert a block containing one or more blocks :
insert my-file [
["Record 1" 1 2 3]
["Record 2" 2 3 4]
]
If you want to insert one record containing blocks, you can une the /only refinement:
insert/only my-file [
["Value 1"]
["Value 2"]
]
To insert data at end of the file, use the standard append function :
insert my-file ["data 1" "data 2" 3 4]
To insert data for example at the third position, use the standard at function :
my-file: at my-file 3 insert my-file ["data 1" "data 2" 3 4]
To change data, use the standard change function :
my-file: open DATA:my-data-file.data my-file: at my-file 3 change my-file ["data 1" "data 2" 3 4] close my-file
This example change the third record.
If you want to change many records, you can change a block containing one or more blocks :
change my-file [
["Record 1" 1 2 3]
["Record 2" 2 3 4]
]
If you want to change one record containing blocks, you can une the /only refinement:
change/only my-file [
["Value 1"]
["Value 2"]
]
If you want to change for example 1 by 3 record, you can use the /part refinement
change/part my-file [
["Record 1" 1 2 3]
["Record 2" 2 3 4]
["Record 3" 4 5 6]
] 1
To remove record (s), use the standard remove function :
remove my-file
If you want to remove many record, use the /part refinement. For example, to to remove 3 records, do this :
remove/part my-file 3
To get data, you can use either the standard copy or pick function
probe pick my-file 1 probe copy my-file
With the copy function you can use the /part refinement:
probe copy/part my-file 5
With file protocol, you can it as for series
You can sort the records in the file. It’s very usefull and can be done like this
my-file: open data:my-file.data sort my-file close my-file
With file protocol, you can manage file and directory. This can done in the same way as standard file.
You can use the following function :
query to obtain file or directory information exists to verify if a file or directory exists make-dir to create a directory delete to delete a file or directory
query data:my-file.data exsits data:my-file.data make-dir data:my-directory/ delete/any data:my-directory/*.data
For each database, the table file structure is stored in a file.
schema.ctl is used for default database type. It’s a standard REBOL script file which is simple loaded when the database is opened. schema.ini is used for {Microsoft text driver} database. It’s a standard .ini file
All the table files are stored in the same directory as the schema file.
In schema.ctl file, SQL-PROTOCOL store the schema structure in the following manner :
table-name: [
scheme: table-file-schema
target: table-file-name
schema: [
cols: [
col-specs-1
...
col-specs-n
]
property-1: value-1
...
property-n: value-n
]
]
col-specs = col-name col-specs = [col-name col-type col-length]
The schema.ctl is not implemented like this now, but this will be done soon. Actualy, the schema is stored in a database.ctl file with a different format
Example schema for DATA or HEAP protocol :
data-table: [
scheme: 'DATA
target: %data-table.data
schema: [
cols: [
col-1 ; untyped column
[col-2 date!] ; a date
]
]
]
Example schema for CSV or FIXED protocol :
csv-table: [
scheme: 'CSV
target: %csv-table.csv
schema: [
ColnameHeader: false
format: 'Delimited
delimiter: ";"
cols: [
col-1 ; untyped column
[col-2 char 32] ; 32 char
]
]
]
The schema.ini file is compatible with the {Microsoft text driver (*.csv *.txt)} You can find the specification here :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcjetschema_ini_file.asp
The schema.ini is not implemented now, but this will be done soon.
Here is an example of schema.ini with all possible columns type :
[csvdelimited.csv] ColNameHeader=True Format=CSVDelimited MaxScanRows=0 CharacterSet=OEM Col1=F01 Bit Col2=F02 Byte Col3=F03 Char Width 255 Col4=F04 Currency Col5=F05 Date Col6=F06 Float Col7=F07 Integer Col8=F08 LongChar Col9=F09 Short Col10=F10 Single [fixedlength.txt] ColNameHeader=True Format=FixedLength MaxScanRows=0 CharacterSet=OEM Col1=F01 Bit Width 1 Col2=F02 Byte Width 3 Col3=F03 Char Width 10 Col4=F04 Currency Width 15 Col5=F05 Date Width 6 Col6=F06 Float Width 21 Col7=F07 Integer Width 11 Col8=F08 LongChar Width 32 Col9=F09 Short Width 5 Col10=F10 Single Width 255
I decided to use file protocol to acces to table data. This choice is motivated by two reason :
The interface of all protocol is standardised, so I didn’t need to reinvente the wheel These protocol can be use also outside the database so it can be usefull for other application. One important point was to implemement the directory capability so I can reused the standard function for the creation and deletion of table file.
Also, by implementing the HEAP protocol, I could use always the same interface even if data could be stored in a simple block in memory.
I use a unique SELECT strategy, it’s a table scan / nested loop algorithm.
The algorithm is quiet simple, for each table in the SELECT, the script scan all the row of the table, and for each row, scan all the rows of the next table, and when it’s the last table, the where clause is simply applied.
The speed performance is not verw good but that’s enough with small table and few join. In fact, what is most time consuming, it’s the insert in the resulting block when thousand of rows are inserted.
DATA, HEAP and CSV protocols are quiet well tested. SQL protocol is quiet well tested with DATA, HEAP and CSV table. SQL SELECT, UPDATE and DELETE are quiet well tested SQL CREATE and DROP are tested but they need more tests.
Incomplete list
certainly with a completely database organisation in order to store all the tables and also the schema in one unique file.
0.0.1 [15-Sep-2004 {Initial alpha version} marco@adyreb.org]
0.0.2 [16-Sep-2004 {Documentation & order bug correction & tests} marco@adyreb.org]
0.0.3 [17-Sep-2004 {Change path notation to dot notation for columns} marco@adyreb.org]
0.0.4 [20-Sep-2004 {Add table alias and where normalization} marco@adyreb.org]
0.0.5 [21-Sep-2004 {Interface stabilization, sort improvement} marco@adyreb.org]
0.0.6 [22-Sep-2004 {First optimization and select * or select table.* implementation} marco@adyreb.org]
0.0.7 [27-Sep-2004 {RAPID Documentation, to-rebol-cols debugging and order interface change} marco@adyreb.org]
0.1.0 [28-Sep-2004 {Change in provision of SQl protocol - DATA: protocol & database object} marco@adyreb.org]
0.1.1 [29-Sep-2004 {Change of test case & documentation & SQL: protocol} marco@adyreb.org]
0.1.2 [30-Sep-2004 {Dismiss of RAPID documentation & various changes} marco@adyreb.org]
0.1.3 [04-Oct-2004 {Transient debug & developpment of sql INSERT, UPDATE & DELETE} marco@adyreb.org]
0.1.4 [06-Oct-2004 {Change in UPDATE syntaxe and DELETE debug} marco@adyreb.org]
0.1.5 [08-Oct-2004 {Major change to resolve the path problem} marco@adyreb.org]
0.1.6 [11-Oct-2004 {Implements HEAP protocol for transient table} marco@adyreb.org]
0.1.7 [12-Oct-2004 {Implements CREATE/DROP TABLE and HEAP & DATA optimization} marco@adyreb.org]
0.1.8 [13-Oct-2004 {Improve path an target management & add get-url function} marco@adyreb.org]
0.2.0 [13-Oct-2004 {First alpha published on www.rebol.org} marco@adyreb.org]
0.2.1 [15-Oct-2004 {Change on the data protocol - implement directory management} marco@adyreb.org]
0.2.2 [18-Oct-2004 {Try to improve select performance} marco@adyreb.org]
0.2.3 [27-Oct-2004 {Change on the data and heap protocol - improve directory management} marco@adyreb.org]
0.3.0 [11-Nov-2004 {Add CSV protocol, change on DATA protocol and preparation to FIXED protocol} marco@adyreb.org]
0.3.1 [19-Nov-2004 {Various bug correction and header extension} marco@adyreb.org]
0.3.2 [14-Nov-2004 {Add SORT on DATA and CSV protocol plus bug correction (thank Shad)} marco@adyreb.org]
0.4.0 [14-Dec-2004 {Implement new schema.ctl and extend TYPE = clause} marco@adyreb.org]
0.4.1 [20-Dec-2004 {Implement schema.ini and extend test case} marco@adyreb.org]
0.4.2 [10-Jan-2005 {Test, debug and correction on port/local/table and schema.ctl} marco@adyreb.org]
0.4.3 [13-Jan-2005 {Lot of test, debug and correction on compatibility with Microsoft Text Driver} marco@adyreb.org]
0.5.0 [17-Jan-2005 {Alpha version published on www.rebol.org} marco@adyreb.org]
You can find the sql-protocol.zip archive in the french framework here :
http://www.agora-dev.org/forums/view.php?site=rebol&bn=rebol_protocols&key=1095276031
The archive contains :
Text File Format.doc The microsoft CSV file specification