--- /srv/reproducible-results/rbuild-debian/r-b-build.jWInkSw1/b1/libgnatcoll-db_23.0.0-4_armhf.changes +++ /srv/reproducible-results/rbuild-debian/r-b-build.jWInkSw1/b2/libgnatcoll-db_23.0.0-4_armhf.changes ├── Files │ @@ -1,11 +1,11 @@ │ │ 39f0e9a0162bbe91a55d248267ec83bf 362108 debug optional libgnatcoll-db-bin-dbgsym_23.0.0-4_armhf.deb │ eedc94f0a60f3b883ba241216c352415 187976 devel optional libgnatcoll-db-bin_23.0.0-4_armhf.deb │ - 54f33a968fec059f9bdb410f518d91e6 453776 doc optional libgnatcoll-db-doc_23.0.0-4_all.deb │ + 5280c8affe70c6db1084d8a7ea9152eb 453676 doc optional libgnatcoll-db-doc_23.0.0-4_all.deb │ d95600bee6d885f88f0073cc341d2c73 211860 debug optional libgnatcoll-postgres1-dbgsym_23.0.0-4_armhf.deb │ e5fd7e78f0b5729ffbd1120042d409b7 119384 libs optional libgnatcoll-postgres1_23.0.0-4_armhf.deb │ 07942b62f11d55906b49bf153e6ebb0e 142872 libdevel optional libgnatcoll-postgres3-dev_23.0.0-4_armhf.deb │ 46255c3dbfd0fb47d1dbce83afdb24c1 1843220 debug optional libgnatcoll-sql3-dbgsym_23.0.0-4_armhf.deb │ 3ebc9ca4ce972eda418a6ef9cddc9449 928684 libs optional libgnatcoll-sql3_23.0.0-4_armhf.deb │ 7450851f11b4ecc364220a0e5af519d3 1147524 libdevel optional libgnatcoll-sql5-dev_23.0.0-4_armhf.deb │ da45a736181ce0c55eb8ff4a89f19439 50492 debug optional libgnatcoll-sqlite20-dbgsym_23.0.0-4_armhf.deb ├── libgnatcoll-db-doc_23.0.0-4_all.deb │ ├── file list │ │ @@ -1,3 +1,3 @@ │ │ -rw-r--r-- 0 0 0 4 2023-05-10 21:15:55.000000 debian-binary │ │ --rw-r--r-- 0 0 0 1604 2023-05-10 21:15:55.000000 control.tar.xz │ │ --rw-r--r-- 0 0 0 451980 2023-05-10 21:15:55.000000 data.tar.xz │ │ +-rw-r--r-- 0 0 0 1600 2023-05-10 21:15:55.000000 control.tar.xz │ │ +-rw-r--r-- 0 0 0 451884 2023-05-10 21:15:55.000000 data.tar.xz │ ├── control.tar.xz │ │ ├── control.tar │ │ │ ├── ./md5sums │ │ │ │ ├── ./md5sums │ │ │ │ │┄ Files differ │ ├── data.tar.xz │ │ ├── data.tar │ │ │ ├── file list │ │ │ │ @@ -40,15 +40,15 @@ │ │ │ │ -rw-r--r-- 0 root (0) root (0) 607 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/objects.inv │ │ │ │ -rw-r--r-- 0 root (0) root (0) 3886 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/search.html │ │ │ │ -rw-r--r-- 0 root (0) root (0) 23062 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/searchindex.js │ │ │ │ -rw-r--r-- 0 root (0) root (0) 184070 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/sql.html │ │ │ │ -rw-r--r-- 0 root (0) root (0) 34287 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/xref.html │ │ │ │ drwxr-xr-x 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/text/ │ │ │ │ -rw-r--r-- 0 root (0) root (0) 1169 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/text/index.txt │ │ │ │ --rw-r--r-- 0 root (0) root (0) 31611 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/text/sql.txt.gz │ │ │ │ +-rw-r--r-- 0 root (0) root (0) 31506 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/text/sql.txt.gz │ │ │ │ -rw-r--r-- 0 root (0) root (0) 6534 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/text/xref.txt.gz │ │ │ │ drwxr-xr-x 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc-base/ │ │ │ │ -rw-r--r-- 0 root (0) root (0) 670 2023-05-10 21:09:43.000000 ./usr/share/doc-base/libgnatcoll-db-doc.gnatcoll-db │ │ │ │ lrwxrwxrwx 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/_static/_sphinx_javascript_frameworks_compat.js -> ../../../../javascript/sphinxdoc/1.0/_sphinx_javascript_frameworks_compat.js │ │ │ │ lrwxrwxrwx 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/_static/css/badge_only.css -> ../../../../../sphinx_rtd_theme/static/css/badge_only.css │ │ │ │ lrwxrwxrwx 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/_static/css/theme.css -> ../../../../../sphinx_rtd_theme/static/css/theme.css │ │ │ │ lrwxrwxrwx 0 root (0) root (0) 0 2023-05-10 21:15:55.000000 ./usr/share/doc/libgnatcoll-db-doc/html/_static/doctools.js -> ../../../../javascript/sphinxdoc/1.0/doctools.js │ │ │ ├── ./usr/share/doc/libgnatcoll-db-doc/text/sql.txt.gz │ │ │ │ ├── sql.txt │ │ │ │ │ @@ -31,33 +31,33 @@ │ │ │ │ │ this place is organized into tables, each of which contains a number │ │ │ │ │ of fields. A row in a table represents one object. The set of tables │ │ │ │ │ and their fields is called the **schema** of the database. │ │ │ │ │ │ │ │ │ │ Traditionally, writing the SQL queries is done inline: special markers │ │ │ │ │ are inserted into your code to delimit sections that contain SQL code │ │ │ │ │ (as opposed to Ada code), and these are then preprocessed to generate │ │ │ │ │ -actual code. This isn’t the approach chosen in GNATColl: there are │ │ │ │ │ +actual code. This isn't the approach chosen in GNATColl: there are │ │ │ │ │ several drawbacks, in particular your code is no longer Ada and │ │ │ │ │ various tools will choke on it. │ │ │ │ │ │ │ │ │ │ The other usual approach is to write the queries as strings, which are │ │ │ │ │ passed, via a DBMS-specific API, to the DBMS server. This approach is │ │ │ │ │ very fragile: │ │ │ │ │ │ │ │ │ │ * The string might not contain **well-formed** SQL. This will │ │ │ │ │ unfortunately only be detected at run time when the DBMS complains. │ │ │ │ │ │ │ │ │ │ * This is not **type safe**. You might be comparing a text field with │ │ │ │ │ an integer, for instance. In some cases, the DBMS will accept that │ │ │ │ │ - (sqlite for instance), but in some other cases it won’t │ │ │ │ │ + (sqlite for instance), but in some other cases it won't │ │ │ │ │ (PostgreSQL). The result might then either raise an error, or return │ │ │ │ │ an empty list. │ │ │ │ │ │ │ │ │ │ * There is a risk of **SQL injection**. Assuming the string is │ │ │ │ │ - constructed dynamically (using Ada’s *&* operator), it might be easy │ │ │ │ │ + constructed dynamically (using Ada's *&* operator), it might be easy │ │ │ │ │ for a user to pass a string that breaks the query, and even destroys │ │ │ │ │ things in the database. │ │ │ │ │ │ │ │ │ │ * As discussed previously, the SQL code might not be **portable** │ │ │ │ │ across DBMS. For instance, creating an automatically increment │ │ │ │ │ integer primary key in a table is DBMS specific. │ │ │ │ │ │ │ │ │ │ @@ -158,15 +158,15 @@ │ │ │ │ │ 1.2. Database example │ │ │ │ │ ===================== │ │ │ │ │ │ │ │ │ │ This section describes an example that will be extended throughout │ │ │ │ │ this chapter. We will build an application that represents a library. │ │ │ │ │ Such a library contains various media (books and DVDs for instance), │ │ │ │ │ and customers. A customer can borrow multiple media at the same time, │ │ │ │ │ -but a media is either at a customer’s, or still in the library. │ │ │ │ │ +but a media is either at a customer's, or still in the library. │ │ │ │ │ │ │ │ │ │ The GNATColl distribution includes an example directory which contains │ │ │ │ │ all the code and data for this example. │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 1.3. Database schema │ │ │ │ │ ==================== │ │ │ │ │ @@ -182,15 +182,15 @@ │ │ │ │ │ fully described later (The gnatcoll_db2ada tool). However, the input │ │ │ │ │ is always the same: this is the schema of your database, that is the │ │ │ │ │ list of tables and fields that make up your database. There exist two │ │ │ │ │ ways to provide that information: │ │ │ │ │ │ │ │ │ │ * From a running database │ │ │ │ │ │ │ │ │ │ - If you pass the DBMS vendor (postgresql, sqlite,…) and the │ │ │ │ │ + If you pass the DBMS vendor (postgresql, sqlite,...) and the │ │ │ │ │ connection parameters to *gnatcoll_db2ada*, it is able to query the │ │ │ │ │ schema on its own. However, this should not be the preferred method: │ │ │ │ │ this is similar to reverse engineering assembly code into the │ │ │ │ │ original high-level code, and some semantic information will be │ │ │ │ │ missing. For instance, in SQL we have to create tables just to │ │ │ │ │ represent the many-to-many relationships. These extra tables are │ │ │ │ │ part of the implementation of the schema, but are just noise when it │ │ │ │ │ @@ -208,124 +208,124 @@ │ │ │ │ │ below and the ORM). │ │ │ │ │ │ │ │ │ │ The most convenient editor for this file is Emacs, using the *org- │ │ │ │ │ mode* which provides convenient key shortcuts for editing the │ │ │ │ │ contents of ASCII tables. But any text editor will do, and you do │ │ │ │ │ not need to align the columns in this file. │ │ │ │ │ │ │ │ │ │ - All lines starting with a hash sign (‘#’) will be ignored. │ │ │ │ │ + All lines starting with a hash sign ('#') will be ignored. │ │ │ │ │ │ │ │ │ │ This file is a collection of ASCII tables, each of which relates to │ │ │ │ │ one table or one SQL view in your database. The paragraphs start │ │ │ │ │ with a line containing: │ │ │ │ │ │ │ │ │ │ table ::= │ │ │ │ │ '|' ('ABSTRACT')? ('TABLE'|'VIEW') ['(' supertable ')'] │ │ │ │ │ '|' '|' │ │ │ │ │ │ │ │ │ │ - “name” is the name of the table. The third pipe and third column are │ │ │ │ │ + "name" is the name of the table. The third pipe and third column are │ │ │ │ │ optional, and should be used to specify the name for the element │ │ │ │ │ represented by a single row. For instance, if the table is called │ │ │ │ │ - “books”, the third column could contain “book”. This is used when │ │ │ │ │ + "books", the third column could contain "book". This is used when │ │ │ │ │ generating objects for use with *GNATCOLL.SQL.ORM*. │ │ │ │ │ │ │ │ │ │ If the first line starts with the keyword *ABSTRACT*, then no │ │ │ │ │ instance of that table actually exists in the database. This is used │ │ │ │ │ in the context of table inheritance, so define shared fields only │ │ │ │ │ once among multiple tables. │ │ │ │ │ │ │ │ │ │ The keyword *TABLE* can be followed by the name of a table from │ │ │ │ │ which it inherits the fields. Currently, that supertable must be │ │ │ │ │ abstract, and the fields declared in that table are simply │ │ │ │ │ duplicated in the new table. │ │ │ │ │ │ │ │ │ │ Following the declaration of the table, the file then describe their │ │ │ │ │ fields, each on a separate line. Each of these lines must start with │ │ │ │ │ - a pipe character (“|”), and contain a number of pipe-separated │ │ │ │ │ + a pipe character ("|"), and contain a number of pipe-separated │ │ │ │ │ fields. The order of the fields is always given by the following │ │ │ │ │ grammar: │ │ │ │ │ │ │ │ │ │ fields ::= │ │ │ │ │ '|' '|' │ │ │ │ │ '|' ('PK'|''|'NULL'|'NOT NULL'|'INDEX'|'UNIQUE'|'NOCASE') │ │ │ │ │ '|' [default] '|' [doc] '|' │ │ │ │ │ │ │ │ │ │ - The type of the field is the SQL type (“INTEGER”, “TEXT”, │ │ │ │ │ - “TIMESTAMP”, “DATE”, “DOUBLE PRECISION”, “MONEY”, “BOOLEAN”, “TIME”, │ │ │ │ │ - “CHARACTER(1)”). Any maximal length can be specified for strings, │ │ │ │ │ + The type of the field is the SQL type ("INTEGER", "TEXT", │ │ │ │ │ + "TIMESTAMP", "DATE", "DOUBLE PRECISION", "MONEY", "BOOLEAN", "TIME", │ │ │ │ │ + "CHARACTER(1)"). Any maximal length can be specified for strings, │ │ │ │ │ not just 1 as in this example. The tool will automatically convert │ │ │ │ │ these to Ada when generating Ada code. A special type │ │ │ │ │ - (“AUTOINCREMENT”) is an integer that is automatically incremented │ │ │ │ │ + ("AUTOINCREMENT") is an integer that is automatically incremented │ │ │ │ │ according to available ids in the table. The exact type used will │ │ │ │ │ depend on the specific DBMS. │ │ │ │ │ │ │ │ │ │ - The property ‘NOCASE’ indicates that comparison should be case │ │ │ │ │ + The property 'NOCASE' indicates that comparison should be case │ │ │ │ │ insensitive for this field. │ │ │ │ │ │ │ │ │ │ If the field is a foreign key (that is a value that must correspond │ │ │ │ │ to a row in another table), you can use the special syntax for its │ │ │ │ │ type: │ │ │ │ │ │ │ │ │ │ fk_type ::= 'FK' [ '(' ')' ] │ │ │ │ │ │ │ │ │ │ As you can see, the type of the field is not specified explicitly, │ │ │ │ │ - but will always be that of the foreign table’s primary key. With │ │ │ │ │ + but will always be that of the foreign table's primary key. With │ │ │ │ │ this syntax, the foreign table must have a single field for its │ │ │ │ │ primary key. GNATColl does not force a specific order for the │ │ │ │ │ declaration of tables: if is valid to have a foreign key to a table │ │ │ │ │ - that hasn’t been declared yet. There is however a restriction if you │ │ │ │ │ + that hasn't been declared yet. There is however a restriction if you │ │ │ │ │ use the model to create a sqlite database (through the *-createdb* │ │ │ │ │ switch of *gnatcoll_db2ada*): in this case, a reference to a table │ │ │ │ │ - that hasn’t been defined yet may not be not through a field marked │ │ │ │ │ + that hasn't been defined yet may not be not through a field marked │ │ │ │ │ as NOT NULL. This is a limitation of the sqlite backend itself. The │ │ │ │ │ solution in this case is to reorder the declaration of tables, or │ │ │ │ │ drop the NOT NULL constraint. │ │ │ │ │ │ │ │ │ │ Another restriction is that a foreign key that is also a primary key │ │ │ │ │ must reference a table that has already been defined. You need to │ │ │ │ │ reorder the declaration of your tables to ensure this is the case. │ │ │ │ │ │ │ │ │ │ - “reverse_name” is the optional name that will be generated in the │ │ │ │ │ + "reverse_name" is the optional name that will be generated in the │ │ │ │ │ Ada code for the reverse relationship, in the context of │ │ │ │ │ - *GNATCOLL.SQL.ORM*. If the “reverse_name” is empty (the parenthesis │ │ │ │ │ + *GNATCOLL.SQL.ORM*. If the "reverse_name" is empty (the parenthesis │ │ │ │ │ are shown), no reverse relationship is generated. If the parenthesis │ │ │ │ │ and the reverse_name are both omitted, a default name is generated │ │ │ │ │ based on the name of the field. │ │ │ │ │ │ │ │ │ │ The third column in the fields definition indicates the constraints │ │ │ │ │ of the type. Multiple keywords can be used if they are separated by │ │ │ │ │ - commas. Thus, “NOT NULL, INDEX” indicates a column that must be set │ │ │ │ │ + commas. Thus, "NOT NULL, INDEX" indicates a column that must be set │ │ │ │ │ by the user, and for which an index is created to speed up look ups. │ │ │ │ │ │ │ │ │ │ - * A primary key (“PK”) │ │ │ │ │ + * A primary key ("PK") │ │ │ │ │ │ │ │ │ │ - * The value must be defined (“NOT NULL”) │ │ │ │ │ + * The value must be defined ("NOT NULL") │ │ │ │ │ │ │ │ │ │ - * The value can be left undefined (“NULL”) │ │ │ │ │ + * The value can be left undefined ("NULL") │ │ │ │ │ │ │ │ │ │ - * A unique constraint and index (“UNIQUE”) │ │ │ │ │ + * A unique constraint and index ("UNIQUE") │ │ │ │ │ │ │ │ │ │ - * An index should be created for that column (“INDEX”) to speed up │ │ │ │ │ + * An index should be created for that column ("INDEX") to speed up │ │ │ │ │ the lookups. │ │ │ │ │ │ │ │ │ │ * The automatic index created for a Foreign Key should not be │ │ │ │ │ - created (“NOINDEX”). Every time a field references another table, │ │ │ │ │ + created ("NOINDEX"). Every time a field references another table, │ │ │ │ │ GNATColl will by default create an index for it, so that the ORM │ │ │ │ │ - can more efficiently do a reverse query (from the target table’s │ │ │ │ │ + can more efficiently do a reverse query (from the target table's │ │ │ │ │ row find all the rows in the current table that reference that │ │ │ │ │ target row). This will in general provide more efficiency, but in │ │ │ │ │ some cases you never intend to do the reverse query and thus can │ │ │ │ │ spare the extra index. │ │ │ │ │ │ │ │ │ │ The fourth column gives the default value for the field, and is │ │ │ │ │ given in SQL syntax. Strings must be quoted with single quotes. │ │ │ │ │ │ │ │ │ │ The fifth column contains documentation for the field (if any). This │ │ │ │ │ documentation will be included in the generated code, so that IDEs │ │ │ │ │ - can provide useful tooltips when navigating your application’s code. │ │ │ │ │ + can provide useful tooltips when navigating your application's code. │ │ │ │ │ │ │ │ │ │ After all the fields have been defined, you can specify extract │ │ │ │ │ constraints on the table. In particular, if you have a foreign key │ │ │ │ │ to a table that uses a tuple as its primary key, you can define that │ │ │ │ │ foreign key on a new line, as: │ │ │ │ │ │ │ │ │ │ FK ::= '|' "FK:" '|' '|' * │ │ │ │ │ @@ -347,37 +347,37 @@ │ │ │ │ │ The same way the unique multi-column constraint and index can be │ │ │ │ │ created. The name is optional. │ │ │ │ │ │ │ │ │ │ TABLE | tableA | │ │ │ │ │ UNIQUE: | field1,field2,field3 | name | │ │ │ │ │ │ │ │ │ │ Going back to the example we described earlier (Database example), │ │ │ │ │ - let’s describe the tables that are involved. │ │ │ │ │ + let's describe the tables that are involved. │ │ │ │ │ │ │ │ │ │ The first table contains the customers. Here is its definition: │ │ │ │ │ │ │ │ │ │ | TABLE | customers | customer || The customer for the library | │ │ │ │ │ | id | AUTOINCREMENT | PK || Auto-generated id | │ │ │ │ │ | first | TEXT | NOT NULL || Customer's first name | │ │ │ │ │ | last | TEXT | NOT NULL, INDEX || Customer's last name | │ │ │ │ │ │ │ │ │ │ We highly recommend to set a primary key on all tables. This is a │ │ │ │ │ field whose value is unique in the table, and thus that can act as │ │ │ │ │ an identifier for a specific row in the table (in this case for a │ │ │ │ │ specific customer). We recommend using integers for these ids for │ │ │ │ │ efficiency reasons. It is possible that the primary key will be made │ │ │ │ │ - of several fields, in which case they should all have the “PK” │ │ │ │ │ + of several fields, in which case they should all have the "PK" │ │ │ │ │ constraint in the third column. │ │ │ │ │ │ │ │ │ │ A table with no primary key is still usable. The difference is in │ │ │ │ │ the code generated for the ORM (The Object-Relational Mapping layer │ │ │ │ │ (ORM)), since the *Delete* operation for this table will raise a │ │ │ │ │ - *Program_Error* instead of doing the actual deletion (that’s because │ │ │ │ │ + *Program_Error* instead of doing the actual deletion (that's because │ │ │ │ │ there is no guaranteed unique identifier for the element, so the ORM │ │ │ │ │ - does not know which one to delete – we do not depend on having │ │ │ │ │ + does not know which one to delete -- we do not depend on having │ │ │ │ │ unique internal ids on the table, like some DBMS have). Likewise, │ │ │ │ │ the elements extracted from such a primary key-less table will not │ │ │ │ │ be cached locally in the session, and cannot be updated (only new │ │ │ │ │ elements can be created in the table). │ │ │ │ │ │ │ │ │ │ As we mentioned, the library contains two types of media, books and │ │ │ │ │ DVDs. Each of those has a title, an author. However, a book also has │ │ │ │ │ @@ -387,15 +387,15 @@ │ │ │ │ │ declare one abstract table (media) which contains the common fields, │ │ │ │ │ and two tables to represent the types of media. │ │ │ │ │ │ │ │ │ │ As we mentioned, a media can be borrowed by at most one customer, │ │ │ │ │ but a customer can have multiple media at any point in time. This is │ │ │ │ │ called a **one-to-many** relationship. In SQL, this is in general │ │ │ │ │ described through the use of a foreign key that goes from the table │ │ │ │ │ - on the “many” side. In this example, we therefore have a foreign key │ │ │ │ │ + on the "many" side. In this example, we therefore have a foreign key │ │ │ │ │ from media to customers. We also provide a name for the reverse │ │ │ │ │ relationship, which will become clearer when we describe the ORM │ │ │ │ │ interface. │ │ │ │ │ │ │ │ │ │ Here are the declarations: │ │ │ │ │ │ │ │ │ │ | ABSTRACT TABLE | media | media || The contents of the library | │ │ │ │ │ @@ -415,15 +415,15 @@ │ │ │ │ │ "dbschema.txt". │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 1.4. The gnatcoll_db2ada tool │ │ │ │ │ ============================= │ │ │ │ │ │ │ │ │ │ As stated in the introduction, one of the goals of this library is to │ │ │ │ │ -make sure the application’s code follows changes in the schema of your │ │ │ │ │ +make sure the application's code follows changes in the schema of your │ │ │ │ │ database. │ │ │ │ │ │ │ │ │ │ To reach this goal, an external tool, "gnatcoll_db2ada" is provided │ │ │ │ │ with GNATColl, and should be spawned as the first step of the build │ │ │ │ │ process, or at least whenever the database schema changes. It │ │ │ │ │ generates an Ada package (*Database* by default) which reflects the │ │ │ │ │ current schema of the database. │ │ │ │ │ @@ -437,15 +437,15 @@ │ │ │ │ │ These parameters specify the connection parameters for the │ │ │ │ │ database. To find out the schema, "gnatcoll_db2ada" can connect to │ │ │ │ │ an existing database (Database schema). The user does not need to │ │ │ │ │ have write permission on the database, since all queries are read- │ │ │ │ │ only. │ │ │ │ │ │ │ │ │ │ *-dbmodel file* │ │ │ │ │ - This parameter can replace the above *-dbname*,… It specifies the │ │ │ │ │ + This parameter can replace the above *-dbname*,... It specifies the │ │ │ │ │ name of a text file that contains the description of the database, │ │ │ │ │ therefore avoiding the need for already having a database up-and- │ │ │ │ │ running to generate the Ada interface. │ │ │ │ │ │ │ │ │ │ The format of this text file was described in the previous section. │ │ │ │ │ │ │ │ │ │ This switch is not compatible with *-enum* and *-vars* that really │ │ │ │ │ @@ -476,21 +476,21 @@ │ │ │ │ │ application, without requiring access to the external files that │ │ │ │ │ define the schema and the initial data. │ │ │ │ │ │ │ │ │ │ *-enum table,id,name,prefix,base* │ │ │ │ │ This parameter can be repeated several times if needed. It │ │ │ │ │ identifies one of the special tables of the database that acts as │ │ │ │ │ an enumeration type. It is indeed often the case that one or more │ │ │ │ │ - tables in the database have a role similar to Ada’s enumeration │ │ │ │ │ + tables in the database have a role similar to Ada's enumeration │ │ │ │ │ types, i.e. contains a list of values for information like the list │ │ │ │ │ - of possible priorities, a list of countries,… Such lists are only │ │ │ │ │ + of possible priorities, a list of countries,... Such lists are only │ │ │ │ │ manipulated by the maintainer of the database, not interactively, │ │ │ │ │ - and some of their values have impact on the application’s code (for │ │ │ │ │ + and some of their values have impact on the application's code (for │ │ │ │ │ instance, if a ticket has an urgent priority, we need to send a │ │ │ │ │ - reminder every day – but the application needs to know what an │ │ │ │ │ + reminder every day -- but the application needs to know what an │ │ │ │ │ urgent priority is). In such a case, it is convenient to generate │ │ │ │ │ these values as constants in the generated package. The output will │ │ │ │ │ be similar to: │ │ │ │ │ │ │ │ │ │ subtype Priority_Id is Integer; │ │ │ │ │ Priority_High : constant Priority_Id := 3; │ │ │ │ │ Priority_Medium : constant Priority_Id := 2; │ │ │ │ │ @@ -513,15 +513,15 @@ │ │ │ │ │ -enum ticket_priorities,Priority,Name,Priority,Integer │ │ │ │ │ │ │ │ │ │ First word in the parameter is the table name where the data to │ │ │ │ │ generate constants is stored. Second word is the field name in the │ │ │ │ │ table where the Ada constant value is stored. The third word is the │ │ │ │ │ field where the last part the Ada constant name is stored. The │ │ │ │ │ forth word is the prefix to add in front of the third word field │ │ │ │ │ - value to generate the Ada constant’s name. The last optional │ │ │ │ │ + value to generate the Ada constant's name. The last optional │ │ │ │ │ parameter should be either *Integer* (default) or *String*, which │ │ │ │ │ influences the way how the Ada constant value is going to be │ │ │ │ │ generated (surrounded or not by quotes). │ │ │ │ │ │ │ │ │ │ *-enum-image* │ │ │ │ │ If specified in addition to the *-enum* switch, then a function is │ │ │ │ │ generated for each *Integer*-valued enum that converts numeric │ │ │ │ │ @@ -560,15 +560,15 @@ │ │ │ │ │ │ │ │ │ │ which generates: │ │ │ │ │ │ │ │ │ │ No_Assigne_Id : constant := 0; │ │ │ │ │ -- help │ │ │ │ │ │ │ │ │ │ The application should use this constant rather than some hard- │ │ │ │ │ - coded string *“unassigned”* or a named constant with the same │ │ │ │ │ + coded string *"unassigned"* or a named constant with the same │ │ │ │ │ value. The reason is that presumably the login will be made visible │ │ │ │ │ somewhere to the user, and we could decide to change it (or │ │ │ │ │ translate it to another language). In such a case, the application │ │ │ │ │ would break. On the other hand, using the constant *0* which we │ │ │ │ │ just extracted will remain valid, whatever the actual text we │ │ │ │ │ display for the user. │ │ │ │ │ │ │ │ │ │ @@ -672,32 +672,32 @@ │ │ │ │ │ a database (or at least its schema). This operation can also be │ │ │ │ │ performed directly from your Ada code by using the services provided │ │ │ │ │ in the *GNATCOLL.SQL.Inspect* package. In particular, there are │ │ │ │ │ services for reading the schema of a database either from a file or │ │ │ │ │ from a live database, just as *gnatcoll_db2ada* does. │ │ │ │ │ │ │ │ │ │ This results in a structure in memory that you can use to find out │ │ │ │ │ -which are the tables, what are their fields, their primary keys,… │ │ │ │ │ +which are the tables, what are their fields, their primary keys,... │ │ │ │ │ │ │ │ │ │ It is also possible to dump this schema to a text file (with the same │ │ │ │ │ format as expected by *-dbmodel*), or more interestingly to output the │ │ │ │ │ SQL statements that are needed to create the tables in a database. In │ │ │ │ │ the case of Sqlite, creating a table will also create the database │ │ │ │ │ -file if it doesn’t exist yet, so no special rights are needed. │ │ │ │ │ +file if it doesn't exist yet, so no special rights are needed. │ │ │ │ │ │ │ │ │ │ This input/output mechanism is implemented through an abstract │ │ │ │ │ *Schema_IO* tagged type, with various concrete implementations (either │ │ │ │ │ *File_Schema_IO* to read or write from/to a file, or *DB_Schema_IO* to │ │ │ │ │ read or write from/to a database). │ │ │ │ │ │ │ │ │ │ See the specs for more detail on these subprograms. │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ -1.4.3. Back to the library example… │ │ │ │ │ ------------------------------------ │ │ │ │ │ +1.4.3. Back to the library example... │ │ │ │ │ +------------------------------------- │ │ │ │ │ │ │ │ │ │ In the previous section, we have described our database schema in a │ │ │ │ │ text file. We will now perform two operations: │ │ │ │ │ │ │ │ │ │ * Create an empty database │ │ │ │ │ │ │ │ │ │ This should of course only be done once, not every time you run your │ │ │ │ │ @@ -760,15 +760,15 @@ │ │ │ │ │ parameters. This is done via a │ │ │ │ │ *GNATCOLL.SQL.Exec.Database_Description* object. The creation of this │ │ │ │ │ object depends on the specific DBMS you are connecting to (and this is │ │ │ │ │ the only part of your code that needs to know about the specific │ │ │ │ │ system). The packages *GNATCOLL.SQL.Postgres* and │ │ │ │ │ *GNATCOLL.SQL.Sqlite* contain a *Setup* function, whose parameters │ │ │ │ │ depend on the DBMS. They provide full documentation for their │ │ │ │ │ -parameters. Let’s take a simple example from sqlite: │ │ │ │ │ +parameters. Let's take a simple example from sqlite: │ │ │ │ │ │ │ │ │ │ with GNATCOLL.SQL.Sqlite; -- or Postgres │ │ │ │ │ declare │ │ │ │ │ DB_Descr : GNATCOLL.SQL.Exec.Database_Description; │ │ │ │ │ begin │ │ │ │ │ DB_Descr := GNATCOLL.SQL.Sqlite.Setup ("dbname.db"); │ │ │ │ │ end │ │ │ │ │ @@ -839,15 +839,15 @@ │ │ │ │ │ critical will appear if you do not close, though, because the │ │ │ │ │ transactions to the DBMS server are saved every time you call *Commit* │ │ │ │ │ in any case. So the code would end with: │ │ │ │ │ │ │ │ │ │ Free (DB); -- for all connections you have opened │ │ │ │ │ Free (DB_Descr); │ │ │ │ │ │ │ │ │ │ -At this point, there still hasn’t been any connection to the DBMS. │ │ │ │ │ +At this point, there still hasn't been any connection to the DBMS. │ │ │ │ │ This will be done the first time a query is executed. If for some │ │ │ │ │ reason the connection to the DBMS server is lost, GNATColl will │ │ │ │ │ automatically attempt to reconnect a number of times before it gives │ │ │ │ │ up. This might break if there was an ongoing SQL transaction, but │ │ │ │ │ simplifies your code since you do not have to handle reconnection when │ │ │ │ │ there was a network failure, for instance. │ │ │ │ │ │ │ │ │ │ @@ -881,28 +881,28 @@ │ │ │ │ │ interface when the DBMS provides one for instance), or via a command │ │ │ │ │ line tool (*psql* for PostgreSQL or *sqlite3* for Sqlite), and start │ │ │ │ │ inserting data manually. This shows one of the nice aspects of using │ │ │ │ │ a standard DBMS for your application: you can alter the database │ │ │ │ │ (for instance to do minor fixes in the data) with a lot of external │ │ │ │ │ tools that were developed specifically for that purpose and that │ │ │ │ │ provide a nice interface. However, this is also tedious and error │ │ │ │ │ - prone, and can’t be repeat easily every time we recreate the │ │ │ │ │ + prone, and can't be repeat easily every time we recreate the │ │ │ │ │ database (for instance before running automatic tests). │ │ │ │ │ │ │ │ │ │ * Using *GNATCOLL.SQL.EXEC* │ │ │ │ │ │ │ │ │ │ As we will describe later, GNATColl contains all the required │ │ │ │ │ machinery for altering the contents of the database and creating new │ │ │ │ │ objects. Using *GNATCOLL.SQL.ORM* this can also be done at a high- │ │ │ │ │ level and completely hide SQL. │ │ │ │ │ │ │ │ │ │ * Loading a data file │ │ │ │ │ │ │ │ │ │ A lot of frameworks call such a file that contains initial data a │ │ │ │ │ - “fixture”. We will use this technique as an example. At the Ada │ │ │ │ │ + "fixture". We will use this technique as an example. At the Ada │ │ │ │ │ level, this is a simple call to *GNATCOLL.SQL.Inspect.Load_Data*. │ │ │ │ │ The package contains a lot more than just this subprogram (The │ │ │ │ │ gnatcoll_db2ada tool): │ │ │ │ │ │ │ │ │ │ declare │ │ │ │ │ File : GNATCOLL.VFS.Virtual_File := Create ("fixture.txt"); │ │ │ │ │ DB : Database_Connection; -- created earlier │ │ │ │ │ @@ -914,15 +914,15 @@ │ │ │ │ │ The format of this file is described just below. │ │ │ │ │ │ │ │ │ │ As we mentioned, GNATColl can load data from a file. The format of │ │ │ │ │ this file is similar to the one that describes the database schema. It │ │ │ │ │ is a set of ASCII tables, each of which describes the data that should │ │ │ │ │ go in a table (it is valid to duplicate tables). Each block starts │ │ │ │ │ with two lines: The first one has two mandatory columns, the first of │ │ │ │ │ -which contains the text “TABLE”, and the second contains the name of │ │ │ │ │ +which contains the text "TABLE", and the second contains the name of │ │ │ │ │ the table you want to fill. The second line should contain as many │ │ │ │ │ columns as there are fields you want to set. Not all the fields of the │ │ │ │ │ table need to have a corresponding column if you want to set their │ │ │ │ │ contents to NULL (provided, of course, that your schema allows it). │ │ │ │ │ For instance, we could add data for our library example as such: │ │ │ │ │ │ │ │ │ │ | TABLE | customers | | │ │ │ │ │ @@ -953,15 +953,15 @@ │ │ │ │ │ | title | author | region | borrowed_by(&last) | │ │ │ │ │ |--------------+-----------+--------+--------------------| │ │ │ │ │ | The Birds | Hitchcock | 1 | &Smith | │ │ │ │ │ | The Dictator | Chaplin | 3 | &Dupont | │ │ │ │ │ │ │ │ │ │ Here, the title of the column indicates that any value in this column │ │ │ │ │ might be a reference to the *customers.last* value. Values which start │ │ │ │ │ -with an ampersand (”&”) will therefore be looked up in │ │ │ │ │ +with an ampersand ("&") will therefore be looked up in │ │ │ │ │ *customers.last*, and the *id* of the corresponding customer will be │ │ │ │ │ inserted in the *dvds* table. It would still be valid to use directly │ │ │ │ │ customer ids instead of references, this is just an extra flexibility │ │ │ │ │ that the references give you to make your fixtures more readable. │ │ │ │ │ │ │ │ │ │ However, if we are using such references we need to provide the │ │ │ │ │ database schema to *Load_Data* so that it can write the proper │ │ │ │ │ @@ -1008,26 +1008,26 @@ │ │ │ │ │ From => Ticket_Priorities, │ │ │ │ │ Where => Ticket_Priorities.Name /= "low", │ │ │ │ │ Group_By => Ticket_Priorities.Category); │ │ │ │ │ end; │ │ │ │ │ │ │ │ │ │ The above example will return, for each type of priority (internal or │ │ │ │ │ customer) the highest possible value. The interest of this query is │ │ │ │ │ -left to the user… │ │ │ │ │ +left to the user... │ │ │ │ │ │ │ │ │ │ This is very similar to an actual SQL query. Field and table names │ │ │ │ │ come from the package that was automatically generated by the │ │ │ │ │ *gnatcoll_db2ada* tool, and therefore we know that our query is only │ │ │ │ │ referencing existing fields. The syntactic correctness is ensured by │ │ │ │ │ standard Ada rules. The *SQL_Select* accepts several parameters │ │ │ │ │ corresponding to the usual SQL attributes like *GROUP BY*, *HAVING*, │ │ │ │ │ *ORDER BY* and *LIMIT*. │ │ │ │ │ │ │ │ │ │ The *From* parameter could be a list of tables if we need to join them │ │ │ │ │ -in some ways. Such a list is created with the overridden *“&”* │ │ │ │ │ +in some ways. Such a list is created with the overridden *"&"* │ │ │ │ │ operator, just as for fields which you can see in the above example. │ │ │ │ │ GNATColl also provides a *Left_Join* function to join two tables when │ │ │ │ │ the second might have no matching field (see the SQL documentation). │ │ │ │ │ │ │ │ │ │ Similar functions exist for *SQL_Insert*, *SQL_Update* and │ │ │ │ │ *SQL_Delete*. Each of those is extensively documented in the │ │ │ │ │ "gnatcoll-sql.ads" file. │ │ │ │ │ @@ -1074,16 +1074,16 @@ │ │ │ │ │ those queries. │ │ │ │ │ │ │ │ │ │ There is another case where GNATColl makes it somewhat easier to write │ │ │ │ │ the queries, and that is to handle joins between tables. If your │ │ │ │ │ schema was build with foreign keys, GNATColl can take advantage of │ │ │ │ │ those. │ │ │ │ │ │ │ │ │ │ -Going back to our library example, let’s assume we want to find out │ │ │ │ │ -all the books that were borrowed by the user “Smith”. We need to │ │ │ │ │ +Going back to our library example, let's assume we want to find out │ │ │ │ │ +all the books that were borrowed by the user "Smith". We need to │ │ │ │ │ involve two tables (*Books* and *Customers*), and provide a join │ │ │ │ │ between them so that the DBMS knows how to associate the rows from one │ │ │ │ │ with the rows from the other. Here is a first example for such a │ │ │ │ │ query: │ │ │ │ │ │ │ │ │ │ Q := SQL_Select │ │ │ │ │ (Fields => Books.Title & Books.Pages, │ │ │ │ │ @@ -1098,15 +1098,15 @@ │ │ │ │ │ (Fields => Books.Title & Books.Pages, │ │ │ │ │ Where => Books.Borrowed_By = Customers.Id │ │ │ │ │ and Customers.Last = "Smith"); │ │ │ │ │ │ │ │ │ │ There is one more things we can do to simplify the query and make it │ │ │ │ │ more solid if the schema of the database changes. For instance, when a │ │ │ │ │ table has a primary key made up of several fields, we need to make │ │ │ │ │ -sure we always have an “=” statement in the WHERE clause for all these │ │ │ │ │ +sure we always have an "=" statement in the WHERE clause for all these │ │ │ │ │ fields between the two tables. In our example above, we could at some │ │ │ │ │ point modify the schema so that the primary key for *customers* is │ │ │ │ │ multiple (this is unlikely in this example of course). To avoid this │ │ │ │ │ potential problems and make the query somewhat easier to read, we can │ │ │ │ │ take advantage of the *FK* subprograms generated by *gnatcoll_db2ada*. │ │ │ │ │ Using the Ada05 dotted notation for the call, we can thus write: │ │ │ │ │ │ │ │ │ │ @@ -1147,15 +1147,15 @@ │ │ │ │ │ variable *R*. │ │ │ │ │ │ │ │ │ │ If for some reason the connection to the database is no longer valid │ │ │ │ │ (a transient network problem for instance), GNATColl will attempt to │ │ │ │ │ reconnect and re-execute your query transparently, so that your │ │ │ │ │ application does not need to handle this case. │ │ │ │ │ │ │ │ │ │ -We’ll describe later (Getting results) how to analyze the result of │ │ │ │ │ +We'll describe later (Getting results) how to analyze the result of │ │ │ │ │ the query. │ │ │ │ │ │ │ │ │ │ Some versions of *Fetch* have an extra parameter *Use_Cache*, set to │ │ │ │ │ *False* by default. If this parameter is true, and the exact same │ │ │ │ │ query has already been executed before, its result will be reused │ │ │ │ │ without even contacting the database server. The cache is │ │ │ │ │ automatically invalidated every hour in any case. This cache is mostly │ │ │ │ │ @@ -1244,15 +1244,15 @@ │ │ │ │ │ SQL_Select │ │ │ │ │ (Fields => Data.Id & Data.Name │ │ │ │ │ From => Data, │ │ │ │ │ Where => Data.Id = Integer_Param (1)); │ │ │ │ │ │ │ │ │ │ GNATColl provides a number of functions (one per type of field) to │ │ │ │ │ indicate that the value is currently unbound. *Integer_Param*, │ │ │ │ │ -*Text_Param*, *Boolean_Param*,… All take a single argument, which is │ │ │ │ │ +*Text_Param*, *Boolean_Param*,... All take a single argument, which is │ │ │ │ │ the index of the corresponding parameter. A query might need several │ │ │ │ │ parameters, and each should have a different index. On the other hand, │ │ │ │ │ the same parameter could be used in several places in the query. │ │ │ │ │ │ │ │ │ │ Although the query above could be executed as is by providing the │ │ │ │ │ values for the parameters, it is more efficient, as we mentioned at │ │ │ │ │ the beginning, to compile it on the server. In theory, this │ │ │ │ │ @@ -1281,40 +1281,40 @@ │ │ │ │ │ reference counted type, that will automatically free the memory on │ │ │ │ │ the server when it goes out of scope. │ │ │ │ │ │ │ │ │ │ * Here, we prepared the statement on the server. If we had specified │ │ │ │ │ *On_Server => False*, we would still have sped things up, since Q │ │ │ │ │ would be converted to a string that can be sent to the DBMS, and │ │ │ │ │ from then on reused that string (note that this conversion is │ │ │ │ │ - specific to each DBMS, since they don’t always represent things the │ │ │ │ │ + specific to each DBMS, since they don't always represent things the │ │ │ │ │ same way, in particular parameters, as we have seen above). Thus │ │ │ │ │ every time you use P you save the time of converting from the │ │ │ │ │ GNATColl tree representation of the query to a string for the DBMS. │ │ │ │ │ │ │ │ │ │ Now that we have a prepared statement, we can simply execute it. If │ │ │ │ │ the statement does not require parameters, the usual *Fetch* and │ │ │ │ │ *Execute* subprograms have versions that work exactly the same with │ │ │ │ │ prepared statements. They also accept a *Params* parameter that │ │ │ │ │ -contains the parameter to pass to the server. A number of *“+”* │ │ │ │ │ +contains the parameter to pass to the server. A number of *"+"* │ │ │ │ │ operators are provided to create those parameters: │ │ │ │ │ │ │ │ │ │ declare │ │ │ │ │ F : Forward_Cursor; │ │ │ │ │ begin │ │ │ │ │ F.Fetch (DB, P, Params => (1 => +2)); │ │ │ │ │ F.Fetch (DB, P, Params => (1 => +3)); │ │ │ │ │ end; │ │ │ │ │ │ │ │ │ │ -Note that for string parameters, the *“+”* operator takes an access to │ │ │ │ │ +Note that for string parameters, the *"+"* operator takes an access to │ │ │ │ │ a string. This is for efficiency, to avoid allocating memory and │ │ │ │ │ copying the string, and is safe because the parameters are only needed │ │ │ │ │ while *Fetch* executes (even for a *Forward_Cursor*. │ │ │ │ │ │ │ │ │ │ Back to our library example. We showed earlier how to write a query │ │ │ │ │ -that retrieves the books borrowed by customer “Smith”. We will now │ │ │ │ │ +that retrieves the books borrowed by customer "Smith". We will now │ │ │ │ │ make this query more general: given a customer name, return all the │ │ │ │ │ books he has borrowed. Since we expect to use this often, we will │ │ │ │ │ prepare it on the server (in real life, this query is of little │ │ │ │ │ interest since the customer name is not unique, we would instead use a │ │ │ │ │ query that takes the id of the customer). In general we would create a │ │ │ │ │ global variable with: │ │ │ │ │ │ │ │ │ │ @@ -1395,15 +1395,15 @@ │ │ │ │ │ previously except by executing the query again. This is in fact only │ │ │ │ │ true if you use a *Forward_Cursor* to fetch the results. │ │ │ │ │ │ │ │ │ │ But GNATColl provides another notion, a *Direct_Cursor*. In this case, │ │ │ │ │ it fetches all the rows in memory when the query executes (thus it │ │ │ │ │ needs to allocate more memory to save every thing, which can be costly │ │ │ │ │ if the query is big). This behavior is supported natively by │ │ │ │ │ -*PostgreSQL*, but doesn’t exist with *sqlite*, so GNATColl will │ │ │ │ │ +*PostgreSQL*, but doesn't exist with *sqlite*, so GNATColl will │ │ │ │ │ simulate it as efficiently as possible. But it will almost always be │ │ │ │ │ faster to use a *Forward_Cursor*. │ │ │ │ │ │ │ │ │ │ In exchange for this extra memory overhead, you can now traverse the │ │ │ │ │ list of results in both directions, as well as access a specific row │ │ │ │ │ directly. It is also possible to know the number of rows that matched │ │ │ │ │ (something hard to do with a *Forward_Cursor* since you would need to │ │ │ │ │ @@ -1508,20 +1508,20 @@ │ │ │ │ │ database interface uses this module to log the queries that are sent │ │ │ │ │ to the server. │ │ │ │ │ │ │ │ │ │ If you activate traces in your application, the user can then activate │ │ │ │ │ one of the following trace handles to get more information on the │ │ │ │ │ exchange that exists between the database and the application. As we │ │ │ │ │ saw before, the output of these traces can be sent to the standard │ │ │ │ │ -output, a file, the system logs,… │ │ │ │ │ +output, a file, the system logs,... │ │ │ │ │ │ │ │ │ │ The following handles are provided: │ │ │ │ │ │ │ │ │ │ * SQL.ERROR This stream is activated by default. Any error returned by │ │ │ │ │ - the database (connection issues, failed transactions,…) will be │ │ │ │ │ + the database (connection issues, failed transactions,...) will be │ │ │ │ │ logged on this stream │ │ │ │ │ │ │ │ │ │ * SQL This stream logs all queries that are not SELECT queries, i.e. │ │ │ │ │ mostly all queries that actually modify the database │ │ │ │ │ │ │ │ │ │ * SQL.SELECT This stream logs all select queries. It is separated from │ │ │ │ │ SQL because very often you will be mostly interested in the queries │ │ │ │ │ @@ -1535,15 +1535,15 @@ │ │ │ │ │ procedure Main is │ │ │ │ │ begin │ │ │ │ │ GNATCOLL.Traces.Parse_Config_File (".gnatdebug"); │ │ │ │ │ ... -- code as before │ │ │ │ │ GNATCOLL.Traces.Finalize; -- reclaim memory │ │ │ │ │ │ │ │ │ │ and then create a .gnatdebug in the directory from which we launch our │ │ │ │ │ -executable. This file would contain a single line containing “+” to │ │ │ │ │ +executable. This file would contain a single line containing "+" to │ │ │ │ │ activate all log streams, or the following to activate only the subset │ │ │ │ │ of fields related to SQL: │ │ │ │ │ │ │ │ │ │ SQL=yes │ │ │ │ │ SQL.SELECT=yes │ │ │ │ │ SQL.LITE=yes │ │ │ │ │ │ │ │ │ │ @@ -1575,15 +1575,15 @@ │ │ │ │ │ function Do_Query (DB, ...) return My_Cursor; │ │ │ │ │ │ │ │ │ │ The idea is that you create a function that does the query for you │ │ │ │ │ (based on some parameters that are not shown here), and then returns a │ │ │ │ │ cursor over the resulting set of rows. For each row, you can use the │ │ │ │ │ *Element* function to get an Ada record for easier manipulation. │ │ │ │ │ │ │ │ │ │ -Let’s first see how these types would be used in practice: │ │ │ │ │ +Let's first see how these types would be used in practice: │ │ │ │ │ │ │ │ │ │ declare │ │ │ │ │ C : My_Cursor := Do_Query (DB, ...); │ │ │ │ │ begin │ │ │ │ │ while Has_Row (C) loop │ │ │ │ │ Put_Line ("Id = " & Element (C).Id); │ │ │ │ │ Next (C); │ │ │ │ │ @@ -1666,15 +1666,15 @@ │ │ │ │ │ objects stored in a database, using a common paradigm called an │ │ │ │ │ object-relational mapping. Such mappings exist for most programming │ │ │ │ │ languages. In the design of GNATColl, we were especially inspired by │ │ │ │ │ the python interface in *django* and *sqlalchemy*, although the last │ │ │ │ │ two rely on dynamic run time introspection and GNATColl relies on code │ │ │ │ │ generation instead. │ │ │ │ │ │ │ │ │ │ -This API is still compatible with *GNATCOLL.SQL*. In fact, we’ll show │ │ │ │ │ +This API is still compatible with *GNATCOLL.SQL*. In fact, we'll show │ │ │ │ │ below cases where the two are mixed. It can also be mixed with │ │ │ │ │ *GNATCOLL.SQL.Exec*, although this might be more risky. Communication │ │ │ │ │ with the DBMS is mostly transparent in the ORM, and it uses various │ │ │ │ │ caches to optimize things and make sure that if you modify an element │ │ │ │ │ the next query(ies) will also return it. If you use │ │ │ │ │ *GNATCOLL.SQL.Exec* directly you are bypassing this cache so you risk │ │ │ │ │ getting inconsistent results in some cases. │ │ │ │ │ @@ -1693,15 +1693,15 @@ │ │ │ │ │ class has foreign keys to other tables. So we remove the *borrowed_by* │ │ │ │ │ field from the *Media* table, and change the *books* table to be: │ │ │ │ │ │ │ │ │ │ | TABLE (media) | books | book | | The books in the library | │ │ │ │ │ | pages | INTEGER | | 100 | | │ │ │ │ │ | borrowed_by | FK customers(borrowed_books) | NULL | | Who borrowed the media | │ │ │ │ │ │ │ │ │ │ -Let’s thus start by generating this code. We can replace the command │ │ │ │ │ +Let's thus start by generating this code. We can replace the command │ │ │ │ │ we ran earlier (with the *-api* switch) with one that will also │ │ │ │ │ generate the ORM API: │ │ │ │ │ │ │ │ │ │ gnatcoll_db2ada -dbmode dbschema.txt -api Database -orm ORM │ │ │ │ │ │ │ │ │ │ The ORM provides a pool of database connections through the package │ │ │ │ │ *GNATCOLL.SQL.Sessions*. A session therefore acts as a wrapper around │ │ │ │ │ @@ -1720,39 +1720,39 @@ │ │ │ │ │ │ │ │ │ │ The first parameter is the same *Database_Description* we saw earlier │ │ │ │ │ (Connecting to the database), but it will be freed automatically by │ │ │ │ │ the sessions package, so you should not free it yourself. │ │ │ │ │ │ │ │ │ │ Once configure, we can now request a session. Through a session, we │ │ │ │ │ can perform queries on the database, make objects persistent, write │ │ │ │ │ -the changes back to the database,…. We configured the session pool to │ │ │ │ │ -have at most 2 sessions. The first time we call *Get_New_Session*, a │ │ │ │ │ -new session will be created in the pool and marked as busy. While you │ │ │ │ │ -have a reference to it in your code (generally as a local variable), │ │ │ │ │ -the session belongs to this part of the code. When the session is no │ │ │ │ │ -longer in scope, it is automatically released to the pool to be reused │ │ │ │ │ -for the next call to *Get_New_Session*. If you call *Get_New_Session* │ │ │ │ │ -a second time while some part of your code holds a session (for │ │ │ │ │ -instance in a different task), a new session will be created. But if │ │ │ │ │ -you do that a third time while the other two are busy, the call to │ │ │ │ │ -*Get_New_Session* is blocking until one of the two sessions is │ │ │ │ │ -released to the pool. │ │ │ │ │ +the changes back to the database,.... We configured the session pool │ │ │ │ │ +to have at most 2 sessions. The first time we call *Get_New_Session*, │ │ │ │ │ +a new session will be created in the pool and marked as busy. While │ │ │ │ │ +you have a reference to it in your code (generally as a local │ │ │ │ │ +variable), the session belongs to this part of the code. When the │ │ │ │ │ +session is no longer in scope, it is automatically released to the │ │ │ │ │ +pool to be reused for the next call to *Get_New_Session*. If you call │ │ │ │ │ +*Get_New_Session* a second time while some part of your code holds a │ │ │ │ │ +session (for instance in a different task), a new session will be │ │ │ │ │ +created. But if you do that a third time while the other two are busy, │ │ │ │ │ +the call to *Get_New_Session* is blocking until one of the two │ │ │ │ │ +sessions is released to the pool. │ │ │ │ │ │ │ │ │ │ This technique ensures optimal use of the resources: we avoid creating │ │ │ │ │ a new session every time (with the performance cost of connecting to │ │ │ │ │ the database), but also avoid creating an unlimited number of sessions │ │ │ │ │ which could saturate the server. Since the sessions are created lazily │ │ │ │ │ the first time they are needed, you can also configure the package │ │ │ │ │ with a large number of sessions with a limited cost. │ │ │ │ │ │ │ │ │ │ -Let’s then take a new session in our code: │ │ │ │ │ +Let's then take a new session in our code: │ │ │ │ │ │ │ │ │ │ Session : constant Session_Type := Get_New_Session; │ │ │ │ │ │ │ │ │ │ -and let’s immediately write our first simple query. A customer comes │ │ │ │ │ +and let's immediately write our first simple query. A customer comes │ │ │ │ │ at the library, handles his card and we see his id (1). We need to │ │ │ │ │ look up in the database to find out who he is. Fortunately, there is │ │ │ │ │ no SQL to write for this: │ │ │ │ │ │ │ │ │ │ C : ORM.Detached_Customer'Class := Get_Customer (Session, Id => 1); │ │ │ │ │ │ │ │ │ │ The call to *Get_Customer* performs a SQL query transparently, using │ │ │ │ │ @@ -1772,15 +1772,15 @@ │ │ │ │ │ your own cursors). This object is no longer valid as soon as the │ │ │ │ │ cursor moves to the next row (in the currently implementation, the │ │ │ │ │ object will describe the next row, but it is best not to rely on │ │ │ │ │ this). As a benefit, this object is light weight and does not make a │ │ │ │ │ copy of the value of the fields, only reference the memory that is │ │ │ │ │ already allocated for the cursor. │ │ │ │ │ │ │ │ │ │ - This object redefines the equality operator (“=”) to compare the │ │ │ │ │ + This object redefines the equality operator ("=") to compare the │ │ │ │ │ primary key fields to get expected results. │ │ │ │ │ │ │ │ │ │ * *Detached_Customer* │ │ │ │ │ │ │ │ │ │ A detached object is very similar to the *Customer* object, but it │ │ │ │ │ will remain valid even if the cursor moves or is destroyed. In fact, │ │ │ │ │ the object has made a copy of the value for all of its fields. This │ │ │ │ │ @@ -1813,15 +1813,15 @@ │ │ │ │ │ │ │ │ │ │ * *Customers_Managers* │ │ │ │ │ │ │ │ │ │ This type is the base type to perform queries on the DBMS. A manager │ │ │ │ │ provides a number of primitive operations which end up creating a │ │ │ │ │ SQL query operation in the background, without making that explicit. │ │ │ │ │ │ │ │ │ │ - Let’s first write a query that returns all books in the database: │ │ │ │ │ + Let's first write a query that returns all books in the database: │ │ │ │ │ │ │ │ │ │ declare │ │ │ │ │ M : Books_Managers := All_Books; │ │ │ │ │ BL : Book_List := M.Get (Session); │ │ │ │ │ B : Book; │ │ │ │ │ begin │ │ │ │ │ while BL.Has_Row loop │ │ │ │ │ @@ -1831,15 +1831,15 @@ │ │ │ │ │ BL.Next; │ │ │ │ │ end loop; │ │ │ │ │ end; │ │ │ │ │ │ │ │ │ │ The manager *M* corresponds to a query that returns all the books in │ │ │ │ │ the database. The second line then executes the query on the │ │ │ │ │ database, and returns a list of books. We then traverse the list. │ │ │ │ │ - Note how we access the book’s title by calling a function, rather │ │ │ │ │ + Note how we access the book's title by calling a function, rather │ │ │ │ │ than by the index of a field as we did with *GNATCOLL.SQL.Exec* with │ │ │ │ │ Value(B, 0). The code is much less fragile this way. │ │ │ │ │ │ │ │ │ │ The line that calls *Borrowed_By* will execute an additional SQL │ │ │ │ │ query for each book. This might be inefficient if there is a large │ │ │ │ │ number of books. We will show later how this can be optimized. │ │ │ │ │ │ │ │ │ │ @@ -1855,15 +1855,15 @@ │ │ │ │ │ As seen in the example above, these are the two functions that │ │ │ │ │ execute the query on the database, and returns a list of objects │ │ │ │ │ (respectively a *Customer_List* and a *Direct_Customer_List*). │ │ │ │ │ │ │ │ │ │ * *Distinct* │ │ │ │ │ │ │ │ │ │ Returns a copy of the manager that does not return twice a row │ │ │ │ │ - with the same data (in SQL, this is the “DISTINCT” operator) │ │ │ │ │ + with the same data (in SQL, this is the "DISTINCT" operator) │ │ │ │ │ │ │ │ │ │ * *Limit* (Count : Natural; From : Natural := 0) │ │ │ │ │ │ │ │ │ │ Returns a copy of the manager that returns a subset of the │ │ │ │ │ results, for instance the first *Count* ones. │ │ │ │ │ │ │ │ │ │ * *Order_By* (By : SQL_Field_List) │ │ │ │ │ @@ -1893,15 +1893,15 @@ │ │ │ │ │ │ │ │ │ │ M : Books_Managers := All_Books.Filter (Condition => Books.Pages < 50); │ │ │ │ │ │ │ │ │ │ More complex conditions are possible, involving other tables. │ │ │ │ │ Currently, the ORM does not have a very user-friendly interface │ │ │ │ │ for those, but you can always do this by falling back partially to │ │ │ │ │ SQL. For instance, if we want to retrieve all the books borrowed │ │ │ │ │ - by user “Smith”, we need to involve the *Customers* table, and │ │ │ │ │ + by user "Smith", we need to involve the *Customers* table, and │ │ │ │ │ thus make a join with the *Books* table. In the future, we intend │ │ │ │ │ to make this join automatic, but for now you will need to write: │ │ │ │ │ │ │ │ │ │ M : Books_Managers := All_Books.Filter │ │ │ │ │ (Books.FK (Customers) │ │ │ │ │ and Customers.Last = "Smith"); │ │ │ │ │ │ │ │ │ │ @@ -1934,15 +1934,15 @@ │ │ │ │ │ will result in a query. So if you pass 2 for *Depth* the data for │ │ │ │ │ book, customers and addresses will be retrieved. │ │ │ │ │ │ │ │ │ │ The second parameter related to efficiency. When a foreign key was │ │ │ │ │ mentioned as *NOT NULL* in the schema, we know it is always │ │ │ │ │ pointing to an existing object in another table. *Select_Related* │ │ │ │ │ will always retrieve such objects. If, however, the foreign key │ │ │ │ │ - can be null, i.e. there isn’t necessarily a corresponding object │ │ │ │ │ + can be null, i.e. there isn't necessarily a corresponding object │ │ │ │ │ in the other table, the SQL query needs to use a *LEFT JOIN*, │ │ │ │ │ which is less efficient. By default, GNATColl will not retrieve │ │ │ │ │ such fields unless *Follow_Left_Join* was set to True. │ │ │ │ │ │ │ │ │ │ In our example, a book is not necessarily borrowed by a customer, │ │ │ │ │ so we need to follow the left joins: │ │ │ │ │ │ │ │ │ │ @@ -1974,19 +1974,19 @@ │ │ │ │ │ -- WHERE books.borrowed_by=1 │ │ │ │ │ │ │ │ │ │ *Borrowed_Books* is a function that was generated because there was a │ │ │ │ │ *reverse_name*. It returns a *Books_Managers*, so we could in fact │ │ │ │ │ further filter the list of borrowed books with the same primitive │ │ │ │ │ operations we just saw. As you can see, the resulting SQL is optimal. │ │ │ │ │ │ │ │ │ │ -Let’s optimize further the initial query. We have hard-coded the │ │ │ │ │ +Let's optimize further the initial query. We have hard-coded the │ │ │ │ │ customer name, but in fact we could be using the same subprograms we │ │ │ │ │ were using for prepared statements (Prepared queries), and even │ │ │ │ │ prepare the query on the server for maximum efficiency. Since our │ │ │ │ │ -application is likely to use this query a lot, let’s create a global │ │ │ │ │ +application is likely to use this query a lot, let's create a global │ │ │ │ │ variable: │ │ │ │ │ │ │ │ │ │ M : constant Books_Managers := All_Books.Filter │ │ │ │ │ (Books.FK (Customers) │ │ │ │ │ and Customers.Id = Integer_Param (1)) │ │ │ │ │ .Select_Related (1, Follow_Left_Join => True); │ │ │ │ │ │ │ │ │ │ @@ -2006,16 +2006,16 @@ │ │ │ │ │ 1.15. Modifying objects in the ORM │ │ │ │ │ ================================== │ │ │ │ │ │ │ │ │ │ The ORM is much more than writing queries. Once the objects are │ │ │ │ │ persistent, they can also be simplify modified, and they will be saved │ │ │ │ │ in the database transparently. │ │ │ │ │ │ │ │ │ │ -Let’s start with a simple example. In the previous section, we │ │ │ │ │ -retrieve an object *C* representing a customer. Let’s change his name, │ │ │ │ │ +Let's start with a simple example. In the previous section, we │ │ │ │ │ +retrieve an object *C* representing a customer. Let's change his name, │ │ │ │ │ and make sure the change is in the database: │ │ │ │ │ │ │ │ │ │ C := Get_Customer (Session, 1); │ │ │ │ │ C.Set_Last ("Smith"); │ │ │ │ │ C.Set_First ("Andrew"); │ │ │ │ │ Session.Commit; │ │ │ │ │ │ │ │ │ │ @@ -2083,15 +2083,15 @@ │ │ │ │ │ CL.Next; │ │ │ │ │ end loop; │ │ │ │ │ │ │ │ │ │ The above example uses *CL.Element*, which is a light-weight │ │ │ │ │ *Customer* object. Such objects will only see the in-memory changes if │ │ │ │ │ you have set *Flush_Before_Query* to true when you configured the │ │ │ │ │ sessions in the call to *GNATCOLL.SQL.Sessions.Setup*. Otherwise, it │ │ │ │ │ -will always return what’s really in the database. │ │ │ │ │ +will always return what's really in the database. │ │ │ │ │ │ │ │ │ │ If the example was using *Detached_Customer* object (by calling │ │ │ │ │ *CL.Element.Detach* for instance) then GNATColl looks up in its │ │ │ │ │ internal cache and returns the cached element when possible. This is a │ │ │ │ │ subtlety, but this is because an *Customer* only exists as long as its │ │ │ │ │ cursor, and therefore cannot be cached in the session. In practice, │ │ │ │ │ the *Flush_Before_Query* should almost always be true and there will │ │ │ │ │ @@ -2104,34 +2104,34 @@ │ │ │ │ │ Often, a database table is used to contain objects that are │ │ │ │ │ semantically of a different kind. In this section, we will take a │ │ │ │ │ slightly different example from the library. We no longer store the │ │ │ │ │ books and the dvds in separate tables. Instead, we have one single │ │ │ │ │ *media* table which contains the title and the author, as well as a │ │ │ │ │ new field *kind* which is either 0 for a book or 1 for a dvd. │ │ │ │ │ │ │ │ │ │ -Let’s now look at all the media borrowed by a customer: │ │ │ │ │ +Let's now look at all the media borrowed by a customer: │ │ │ │ │ │ │ │ │ │ C : constant Customer'Class := Get_Customer (Session, Id => 1); │ │ │ │ │ ML : Media_List := C.Borrowed_Media.Get (Session); │ │ │ │ │ │ │ │ │ │ while ML.Has_Row loop │ │ │ │ │ case ML.Element.Kind is │ │ │ │ │ when 0 => │ │ │ │ │ Put_Line ("A book " & ML.Element.Title); │ │ │ │ │ when 1 => │ │ │ │ │ Put_Line ("A dvd " & ML.Element.Title); │ │ │ │ │ end case; │ │ │ │ │ ML.Next; │ │ │ │ │ end loop; │ │ │ │ │ │ │ │ │ │ -This code works, but requires a case statement. Now, let’s imagine the │ │ │ │ │ +This code works, but requires a case statement. Now, let's imagine the │ │ │ │ │ check out procedure is different for a book and a DVD (for the latter │ │ │ │ │ we need to check that the disk is indeed in the box). We would have │ │ │ │ │ two subprograms *Checkout_Book* and *Checkout_DVD* and call them from │ │ │ │ │ -the case. This isn’t object-oriented programming. │ │ │ │ │ +the case. This isn't object-oriented programming. │ │ │ │ │ │ │ │ │ │ Instead, we will declare two new types: │ │ │ │ │ │ │ │ │ │ type My_Media is abstract new ORM.Detached_Media with private; │ │ │ │ │ procedure Checkout (Self : My_Media) is abstract; │ │ │ │ │ │ │ │ │ │ type Detached_Book is new My_Media with private; │ │ │ │ │ @@ -2145,17 +2145,17 @@ │ │ │ │ │ we would also need to override *Get* so that it returns our new list. │ │ │ │ │ This is tedious. │ │ │ │ │ │ │ │ │ │ We will instead use an element factory in the session. This is a │ │ │ │ │ function that gets a row of a table (in the form of a *Customer*), and │ │ │ │ │ returns the appropriate type to use when the element is detached (by │ │ │ │ │ default, the detached type corresponding to a *Customer* is a │ │ │ │ │ -*Detached_Customer*, and that’s what we want to change). │ │ │ │ │ +*Detached_Customer*, and that's what we want to change). │ │ │ │ │ │ │ │ │ │ -So let’s create such a factory: │ │ │ │ │ +So let's create such a factory: │ │ │ │ │ │ │ │ │ │ function Media_Factory │ │ │ │ │ (From : Base_Element'Class; │ │ │ │ │ Default : Detached_Element'Class) return Detached_Element'Class │ │ │ │ │ is │ │ │ │ │ begin │ │ │ │ │ if From in Media'Class then │ │ │ │ │ ├── encoding │ │ │ │ │ │ @@ -1 +1 @@ │ │ │ │ │ │ -utf-8 │ │ │ │ │ │ +us-ascii