# Limitations

## Global limitations

&LIBGDA;'s global limitations are:

### Multi threaded environment

&LIBGDA; is not thread safe, however it supports working with threads as long as any object (except otherwise stated) created by the API is used by one single thread (that is there is no situation when two threads try to access the same object at the same time). Exceptions are:

- &LIBGDA;'s configuration can be accessed from any thread

- Any object which implements the GdaLockable interface can be accessed from any thread. However one can use the gda_lockable_lock() method to specifically lock an object's usage (especially when getting and setting properties before or after calling methods).

- Any GdaConnection object can be accessed from any thread (that object implements the GdaLockable interface). Specifically &LIBGDA; removes the limits imposed by some database provider's API regarding threads.

- Any GdaAttributesManager can safely be accessed from any thread.

## For MySQL

### Statements execution

- It is not possible to execute a SELECT statement with invalid parameters and with the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag as this feature is currently not implemented.

### Timezone information

Timezone information associated with time and timestamp data types is not stored by MySQL, so when executing statements all the variables containing a time or timestamp information are converted to GMT (timezone 0) before the execution happens. The consequence is that for example if a variable holds the "11:23:55+2" time (11 hours, 23 minutes and 55 seconds, at GMT + 2), then the actual time stored in the database will be "09:23:55", the same time but GMT.

## For Oracle

The following limitations apply to Oracle databases accessed via Libgda:

- At the moment tables' fields schema information retrieval is very slow, so as a work around, use a dictionary to store the database schema and do incremental updates on modified/created tables.

## For PostgreSQL

The following limitations apply to PostgreSQL databases accessed via Libgda:

### BLOB handling

- Postgres uses the "Oid" data type to internally store BLOBs, but this type is also used to store other information within the database. Libgda assumes that any column of type "Oid" represents a blob. If this is not the case, then you must cast it to the correct data type within your SQL query (for example as "SELECT oid::varchar FROM...")

- &LIBGDA; does not try to avoid orphaned BLOBs, to solve the problem of orphaned BLOBs, set up the "lo" extension from PostgreSQL's contrib, and/or use the "vacuumlo" also from the contrib.

  Note that in the future the PostgreSQL's provider will have an option to ensure that there are no orphaned BLOBs itself.

- BLOB manipulations can only occur within a transaction, so you should start a transaction before any operation on BLOBs, otherwise Libgda will automatically start one

### Last inserted row's values

The gda_connection_statement_execute_non_select()'s last_insert_row parameter will return a new GdaSet object only if the table has OIDs (to ensure this, the "WITH OIDS" option should be added at the end of a CREATE TABLE query).

### Statements execution

- It is not possible to execute a SELECT statement with invalid parameters and with the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag if the GDA_STATEMENT_MODEL_CURSOR_FORWARD flag is also specified

### Timezone information

Timezone information associated with time and timestamp data types is not stored by PostgreSQL, so when executing statements all the variables containing a time or timestamp information are converted to GMT (timezone 0) before the execution happens. The consequence is that for example if a variable holds the "11:23:55+2" time (11 hours, 23 minutes and 55 seconds, at GMT + 2), then the actual time stored in the database will be "09:23:55", the same time but GMT.

## For SQLite

The following limitations apply to SQLite databases accessed via Libgda:

### Last inserted row's values

The gda_connection_statement_execute_non_select()'s last_insert_row attribute uses the hidden "_ROWID_" column for each table, but it may fail if the table has a column with the same name, or if the table is defined with the WITHOUT ROWID Optimization.

### Date and time

As SQLite stores dates and times as strings, &LIBGDA; only handles dates in the format recommended by SQLite, which is "YYYY-MM-DD" for dates, "HH:MM:SS" for times and "YYYY-MM-DD HH:MM:SS" for timestamps (see SQLite's documentation).

### Timezone information

Timezone information associated with time and timestamp data types is not stored by PostgreSQL, so when executing statements all the variables containing a time or timestamp information are converted to GMT (timezone 0) before the execution happens. The consequence is that for example if a variable holds the "11:23:55+2" time (11 hours, 23 minutes and 55 seconds, at GMT + 2), then the actual time stored in the database will be "09:23:55", the same time but GMT.

### Error reporting

If there is not enough free space on the disk which stores an SQLite database, you may have some "Disk I/O error" errors. This is also true for meta data connections which are by default created in a temporary location.

## For SQLCipher

The following limitations apply to SQLite database accessed through the SQLCipher database provider. The SQLCipher database provider allows one to connect to a database encrypted using the SQLCipher adaptations to the SQLite database.

The SQLite provider's limitations also apply in this context and it is also currently not possible to uncrypt an encrypted database.

## For LDAP

### User name

LDAP requires a Distinguished Name (DN) to bind a connection. Libgda also accepts a user name which is not a DN; in this case it will first connect anonymously to the server, search for the DN corresponding to the user name, and then bind again using the found DN. The search is done on the "uid" attribute matching the username, and the object class being "inetOrgPerson" (the LDAP filter is "(&(uid=?)(objectclass=inetOrgPerson))" where the question mark is replaced by the username).

### SSL/TLS certificate validation

The TLS_REQCERT and TLS_CACERT options are taken into account by the LDAP provider, and passed to the OpenLDAP library which is actually used. These options are global and set by the first opened LDAP connection (i.e. all other LDAP connections share the same settings, regardless of their TLS_REQCERT and TLS_CACERT options).

The TLS_REQCERT and TLS_CACERT options have a higher priority compared to the options set in the `$HOME/.ldaprc`.

If the server certificate can't he checked (i.e. the certification chain established and verified) when it is required that it be, then the connection will not he established and the returned error will be "Can't contact LDAP server".

## For JDBC based providers

The following limitations apply to databases accessed via Libgda through a JDBC driver. When loading the database providers, &LIBGDA; creates a JDBC provider per JDBC driver found (to work at all it needs to load the Java Virtual Machine (JVM) runtime first).

The JDBC provider is a bit specific since it needs to be installed to be used, but it also requires external JDBC drivers (usually published by the database's editor). As a result, actual JDBC drivers will be useable only when the two conditions are met.

### Last inserted row's values

Not yet supported.