libgda r3255 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite providers/postgres providers/skel-implementation/capi tools
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3255 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite providers/postgres providers/skel-implementation/capi tools
- Date: Fri, 21 Nov 2008 20:40:14 +0000 (UTC)
Author: vivien
Date: Fri Nov 21 20:40:14 2008
New Revision: 3255
URL: http://svn.gnome.org/viewvc/libgda?rev=3255&view=rev
Log:
2008-11-21 Vivien Malerba <malerba gnome-db org>
* libgda/dir-blob-op.c: fixed the "write" virtual method
* tools/gda-sql.c:
- added the "setex" command which sets a parameter either from a table's
value or from the contents of a file (as a blob)
- added the "export" command to export a parameter or a table's value to
a file
- lines starting with a # are considered as a comment and ignored
- added the '-i' option to keep the console after a script has been executed
* libgda/gda-value.[ch]: added gda_value_new_blob_from_file() as a convenience
function
* libgda/gda-column: doc. improvements
* libgda/gda-blob-op.c:
* doc/C:
- improved documentation for provider's developpers about blob operations
- moved the gda_column_set*() to the provider's developpers section
- updated the gda-sql console commands description (.setex end .export commands)
* providers/postgres/gda-postgres-provider.c:
- fixed prepared statement names using static counters to avoid naming collisions
- remove savepoint correction
- better transaction control when using blobs
* providers/postgres/gda-postgres-blob-op.c:
- don't keep the blob "opened" at all times
- correctly handle transaction states when accesing the blob
* providers/postgres/gda-postgres-recordset.h: fixed indentation
* libgda/sqlite/gda-sqlite-provider.c: note for future implementation of
BLOBS
* providers/skel-implementation/capi/gda-capi-blob-op.c:
* providers/skel-implementation/capi/gda-capi-provider.c: corrections to the
default provider's skeleton implementation
Modified:
trunk/ChangeLog
trunk/doc/C/gda-sql-manual.xml
trunk/doc/C/libgda-4.0-sections.txt
trunk/doc/C/prov-writing.xml
trunk/doc/C/tmpl/gda-column.sgml
trunk/doc/C/tmpl/gda-data-select-priv.sgml
trunk/doc/C/tmpl/gda-value.sgml
trunk/libgda/dir-blob-op.c
trunk/libgda/gda-blob-op.c
trunk/libgda/gda-column.c
trunk/libgda/gda-value.c
trunk/libgda/gda-value.h
trunk/libgda/sqlite/gda-sqlite-provider.c
trunk/providers/postgres/gda-postgres-blob-op.c
trunk/providers/postgres/gda-postgres-provider.c
trunk/providers/postgres/gda-postgres-recordset.h
trunk/providers/skel-implementation/capi/gda-capi-blob-op.c
trunk/providers/skel-implementation/capi/gda-capi-provider.c
trunk/tools/gda-sql.c
Modified: trunk/doc/C/gda-sql-manual.xml
==============================================================================
--- trunk/doc/C/gda-sql-manual.xml (original)
+++ trunk/doc/C/gda-sql-manual.xml Fri Nov 21 20:40:14 2008
@@ -20,20 +20,21 @@
<para>
The &LIBGDA;'s console tool' main features are:
<itemizedlist>
- <listitem><para>Can handle more than one connection at the same time</para></listitem>
- <listitem><para>Reports meta data in a similar way, whatever the real type of database
+ <listitem><para>Handle more than one connection at the same time</para></listitem>
+ <listitem><para>Report meta data in a similar way, whatever the real type of database
accessed</para></listitem>
- <listitem><para>Can create <emphasis>virtual</emphasis> connections binding
+ <listitem><para>Create <emphasis>virtual</emphasis> connections binding
several already opened connections (to run SQL commands across multiple
connections)</para></listitem>
- <listitem><para>Allows one to define variables which can be referenced in any
+ <listitem><para>Allow one to define variables which can be referenced in any
SQL statement (using a common syntax)</para></listitem>
- <listitem><para>Has one query buffer per connection to edit complex queries (uses a
+ <listitem><para>One query buffer per connection to edit complex queries (uses a
parametrable external editor)</para></listitem>
<listitem><para>Easy command line editing and output using the Readline library and a
(parametrable) pager</para></listitem>
- <listitem><para>Works on any platform on which &LIBGDA; has been ported to.</para></listitem>
- <listitem><para>Can list, define or remove named data sources (DSN)</para></listitem>
+ <listitem><para>Work on any platform on which &LIBGDA; has been ported to.</para></listitem>
+ <listitem><para>List, define or remove named data sources (DSN)</para></listitem>
+ <listitem><para>Import and export BLOBS (binary large objects) from and to local files</para></listitem>
</itemizedlist>
</para>
</sect1>
@@ -638,11 +639,21 @@
<sect1>
<title>Internal parameters</title>
<para>
- Variables can be defined using the <command>.set</command> command. Variables are then automatically looked for
+ Variables can be defined using the <command>.set</command> and <command>.setex</command> commands.
+ Variables are then automatically looked for
when executing SQL statements for which a variable is required; they are not typed and are converted to
the correct type when needed. Note that variables are shared by all the opened connections.
</para>
<para>
+ When setting values, the textual representation must respect the following format:
+ <itemizedlist>
+ <listitem><para>for booleans: "true" or "false" (case insensitive)</para></listitem>
+ <listitem><para>for numerical types: the dot as a fraction separator</para></listitem>
+ <listitem><para>for dates, time and timestamp: the ISO 8601 format (dates as "YYYY-MM-DD", time as "HH:MM:SS")
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
Use the <command>.set <variablename> <variable value></command> command to define a variable,
and the <command>.set</command> command to list all defined variables. The following example illustrates
variables usage:
@@ -669,6 +680,38 @@
SalesTest>
</programlisting>
</para>
+ <para>
+ The <command>.setex</command> command also sets an internal parameter, it has two usages:
+ <itemizedlist>
+ <listitem><para>The <command>.set <variablename> <filename></command> usage loads the contents
+ of the named filename into the named variable (usually to be used as a BLOB)</para></listitem>
+ <listitem><para>The <command>.set <variablename> <table> <column> <row condition></command>
+ usage creates a named variable which contents is the value of the <table> table and
+ <column> column for the row identified by <row condition>. Note that this command will fail
+ if the <row condition> condition does not return exactly one value.</para>
+ <para>
+ The following example defined a "bl10" variable containing the value of the "blob" column in the "blobs" table
+ for the "id=10" condition:
+ <programlisting>
+.setex bl10 blobs blob "id=10"
+ </programlisting>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The <command>.export</command> command exports to a file the contents of an internal variable or the
+ the contents of a table's value:
+ <itemizedlist>
+ <listitem><para>The <command>.export <variablename> <filename></command> usage exports the contents
+ of the named variable into the named filename</para></listitem>
+ <listitem><para>The <command>.set <table> <column> <row condition> <filename></command>
+ usage exports the value of the <table> table and
+ <column> column for the row identified by <row condition>. Note that this command will fail
+ if the <row condition> condition does not return exactly one value.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
</sect1>
<sect1>
Modified: trunk/doc/C/libgda-4.0-sections.txt
==============================================================================
--- trunk/doc/C/libgda-4.0-sections.txt (original)
+++ trunk/doc/C/libgda-4.0-sections.txt Fri Nov 21 20:40:14 2008
@@ -5,21 +5,13 @@
gda_column_new
gda_column_copy
gda_column_get_name
-gda_column_set_name
gda_column_get_description
-gda_column_set_description
gda_column_get_dbms_type
-gda_column_set_dbms_type
gda_column_get_g_type
-gda_column_set_g_type
gda_column_get_allow_null
-gda_column_set_allow_null
gda_column_get_auto_increment
-gda_column_set_auto_increment
gda_column_get_position
-gda_column_set_position
gda_column_get_default_value
-gda_column_set_default_value
gda_column_get_attribute
gda_column_set_attribute
<SUBSECTION Standard>
@@ -697,6 +689,7 @@
<SECTION>
<FILE>gda-blob-op</FILE>
<TITLE>GdaBlobOp</TITLE>
+<INCLUDE>libgda/gda-blob-op.h</INCLUDE>
GdaBlobOp
gda_blob_op_get_length
gda_blob_op_read
@@ -746,6 +739,7 @@
<SUBSECTION>
GdaBlob
gda_value_new_blob
+gda_value_new_blob_from_file
gda_blob_copy
gda_blob_free
gda_value_get_blob
@@ -1396,6 +1390,15 @@
gda_data_select_take_row
gda_data_select_get_stored_row
gda_data_select_get_connection
+<SUBSECTION>
+gda_column_set_name
+gda_column_set_description
+gda_column_set_dbms_type
+gda_column_set_g_type
+gda_column_set_allow_null
+gda_column_set_auto_increment
+gda_column_set_position
+gda_column_set_default_value
</SECTION>
<SECTION>
Modified: trunk/doc/C/prov-writing.xml
==============================================================================
--- trunk/doc/C/prov-writing.xml (original)
+++ trunk/doc/C/prov-writing.xml Fri Nov 21 20:40:14 2008
@@ -540,7 +540,8 @@
This method is called when the user calls <link linkend="gda-data-model-get-n-rows">gda_data_model_get_n_rows ()</link>.
</para>
<para>
- Note that the number of rows of the data model may not be known until the cursor has reached the
+ Note that the number of rows of the data model may not be known until the cursor has reached the last row of
+ the recordset.
Once known, the number of rows can be stored in the <structfield>advertized_nrows</structfield>'s member of the
<link linkend="GdaDataSelect">GdaDataSelect</link> object.
</para>
@@ -604,31 +605,73 @@
blobs; otherwise binary data may still be used if supported by the database, but the whole binary data is transfered in
the SQL statement which is not suitable for large data.
</para>
+ <para>
+ &LIBGDA; defines <link linkend="GdaBlop">GdaBlob</link> structure which is an extension of the
+ <link linkend="GdaBinary">GdaBinary</link> structure (which contains a pointer to some data and the size of the pointed
+ data). The extension simply adds a pointer to a <link linkend="GdaBlopOp">GdaBlobOp</link> object which has
+ to be implemented by each provider which supports blobs. The following documents the
+ <link linkend="GdaBlopOp">GdaBlobOp</link>'s virtual methods which actually implement the reading from and
+ writing to a blob contained in the database.
+ </para>
+ <para>
+ When reading from a blob in the database or writing to a blob in the database, data read or written is the stored in
+ the <link linkend="GdaBinary">GdaBinary</link> part of the <link linkend="GdaBlopOp">GdaBlobOp</link>.
+ </para>
<sect2>
<title>get_length()</title>
<para>
- To write.
+ This method returns the total length of a blob in bytes. In case of error, -1 is returned and the
+ provider should have added an error (a <link linkend="GdaConnectionEvent">GdaConnectionEvent</link>) to the connection.
</para>
</sect2>
<sect2>
<title>read()</title>
<para>
- To write.
+ This method requests that some data be read from the blob. The data read must be stored in the
+ <link linkend="GdaBinary">GdaBinary</link> part of the <parameter>blob</parameter> parameter. The data to read is
+ the data starting at the <parameter>offset</parameter> offset from the beginning of the blob, and
+ of the <parameter>size</parameter> length.
+ </para>
+ <para>
+ Note that in this method, the <structfield>op</structfield> attribute of the <parameter>blob</parameter>
+ parameter is not used.
+ </para>
+ <para>
+ The returned value is the number of bytes read, or -1 if an error
+ occured (then the provider should have added an error to the connection).
</para>
</sect2>
<sect2>
<title>write()</title>
<para>
- To write.
+ This method requests the some data be written to the blob. The data has to be written
+ in the blob starting at the <parameter>offset</parameter> offset from the beginning of the blob.
+ </para>
+ <para>
+ If the <structfield>op</structfield> attribute of the <parameter>blob</parameter> parameter is not NULL and is different
+ than the <parameter>op</parameter>, then the data to be written is the complete contents of the data stored in the
+ blob represented by the <structfield>op</structfield> attribute of the <parameter>blob</parameter> parameter. Otherwise
+ The data to be written is stored in the
+ <link linkend="GdaBinary">GdaBinary</link> part of the <parameter>blob</parameter>.
+ </para>
+ <para>
+ The returned value is the number of bytes written, or -1 if an error
+ occured (then the provider should have added an error to the connection).
</para>
</sect2>
<sect2>
<title>write_all()</title>
<para>
- To write.
+ This method requests that all the contents of the blob be replaced by some data (if necessary the
+ blob is truncated from its previous length). The data to be written is the same as for the write() method, and
+ the returned value is also the same.
+ </para>
+ <para>
+ If this virtual method is not implemented, then the write() virtual method is used with an <parameter>offset</parameter>
+ parameter of 0.
</para>
</sect2>
</chapter>
Modified: trunk/doc/C/tmpl/gda-column.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-column.sgml (original)
+++ trunk/doc/C/tmpl/gda-column.sgml Fri Nov 21 20:40:14 2008
@@ -71,15 +71,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_name ##### -->
-<para>
-
-</para>
-
- column:
- name:
-
-
<!-- ##### FUNCTION gda_column_get_description ##### -->
<para>
@@ -89,15 +80,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_description ##### -->
-<para>
-
-</para>
-
- column:
- title:
-
-
<!-- ##### FUNCTION gda_column_get_dbms_type ##### -->
<para>
@@ -107,15 +89,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_dbms_type ##### -->
-<para>
-
-</para>
-
- column:
- dbms_type:
-
-
<!-- ##### FUNCTION gda_column_get_g_type ##### -->
<para>
@@ -125,15 +98,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_g_type ##### -->
-<para>
-
-</para>
-
- column:
- type:
-
-
<!-- ##### FUNCTION gda_column_get_allow_null ##### -->
<para>
@@ -143,15 +107,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_allow_null ##### -->
-<para>
-
-</para>
-
- column:
- allow:
-
-
<!-- ##### FUNCTION gda_column_get_auto_increment ##### -->
<para>
@@ -161,15 +116,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_auto_increment ##### -->
-<para>
-
-</para>
-
- column:
- is_auto:
-
-
<!-- ##### FUNCTION gda_column_get_position ##### -->
<para>
@@ -179,15 +125,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_position ##### -->
-<para>
-
-</para>
-
- column:
- position:
-
-
<!-- ##### FUNCTION gda_column_get_default_value ##### -->
<para>
@@ -197,15 +134,6 @@
@Returns:
-<!-- ##### FUNCTION gda_column_set_default_value ##### -->
-<para>
-
-</para>
-
- column:
- default_value:
-
-
<!-- ##### FUNCTION gda_column_get_attribute ##### -->
<para>
Modified: trunk/doc/C/tmpl/gda-data-select-priv.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-data-select-priv.sgml (original)
+++ trunk/doc/C/tmpl/gda-data-select-priv.sgml Fri Nov 21 20:40:14 2008
@@ -73,3 +73,75 @@
@Returns:
+<!-- ##### FUNCTION gda_column_set_name ##### -->
+<para>
+
+</para>
+
+ column:
+ name:
+
+
+<!-- ##### FUNCTION gda_column_set_description ##### -->
+<para>
+
+</para>
+
+ column:
+ title:
+
+
+<!-- ##### FUNCTION gda_column_set_dbms_type ##### -->
+<para>
+
+</para>
+
+ column:
+ dbms_type:
+
+
+<!-- ##### FUNCTION gda_column_set_g_type ##### -->
+<para>
+
+</para>
+
+ column:
+ type:
+
+
+<!-- ##### FUNCTION gda_column_set_allow_null ##### -->
+<para>
+
+</para>
+
+ column:
+ allow:
+
+
+<!-- ##### FUNCTION gda_column_set_auto_increment ##### -->
+<para>
+
+</para>
+
+ column:
+ is_auto:
+
+
+<!-- ##### FUNCTION gda_column_set_position ##### -->
+<para>
+
+</para>
+
+ column:
+ position:
+
+
+<!-- ##### FUNCTION gda_column_set_default_value ##### -->
+<para>
+
+</para>
+
+ column:
+ default_value:
+
+
Modified: trunk/doc/C/tmpl/gda-value.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-value.sgml (original)
+++ trunk/doc/C/tmpl/gda-value.sgml Fri Nov 21 20:40:14 2008
@@ -300,6 +300,15 @@
@Returns:
+<!-- ##### FUNCTION gda_value_new_blob_from_file ##### -->
+<para>
+
+</para>
+
+ filename:
+ Returns:
+
+
<!-- ##### FUNCTION gda_blob_copy ##### -->
<para>
Modified: trunk/libgda/dir-blob-op.c
==============================================================================
--- trunk/libgda/dir-blob-op.c (original)
+++ trunk/libgda/dir-blob-op.c Fri Nov 21 20:40:14 2008
@@ -160,14 +160,14 @@
static glong
gda_dir_blob_op_get_length (GdaBlobOp *op)
{
- GdaDirBlobOp *pgop;
+ GdaDirBlobOp *dirop;
struct stat filestat;
g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
- pgop = GDA_DIR_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
+ dirop = GDA_DIR_BLOB_OP (op);
+ g_return_val_if_fail (dirop->priv, -1);
- if (! g_stat (pgop->priv->complete_filename, &filestat))
+ if (! g_stat (dirop->priv->complete_filename, &filestat))
return filestat.st_size;
else
return -1;
@@ -176,20 +176,20 @@
static glong
gda_dir_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
{
- GdaDirBlobOp *pgop;
+ GdaDirBlobOp *dirop;
GdaBinary *bin;
FILE *file;
size_t nread;
g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
- pgop = GDA_DIR_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
+ dirop = GDA_DIR_BLOB_OP (op);
+ g_return_val_if_fail (dirop->priv, -1);
if (offset >= G_MAXINT)
return -1;
g_return_val_if_fail (blob, -1);
/* open file */
- file = fopen (pgop->priv->complete_filename, "r");
+ file = fopen (dirop->priv->complete_filename, "r");
if (!file)
return -1;
@@ -217,20 +217,20 @@
static glong
gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
{
- GdaDirBlobOp *pgop;
+ GdaDirBlobOp *dirop;
GdaBinary *bin;
FILE *file;
glong nbwritten;
g_return_val_if_fail (GDA_IS_DIR_BLOB_OP (op), -1);
- pgop = GDA_DIR_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
+ dirop = GDA_DIR_BLOB_OP (op);
+ g_return_val_if_fail (dirop->priv, -1);
if (offset >= G_MAXINT)
return -1;
g_return_val_if_fail (blob, -1);
/* open file */
- file = fopen (pgop->priv->complete_filename, "w+");
+ file = fopen (dirop->priv->complete_filename, "w+");
if (!file)
return -1;
@@ -241,10 +241,39 @@
return -1;
}
}
-
- bin = (GdaBinary *) blob;
- nbwritten = fwrite ((char *) (bin->data), 1, bin->binary_length, file);
- fclose (file);
+
+ if (blob->op && (blob->op != op)) {
+ /* use data through blob->op */
+ #define buf_size 16384
+ gint nread = 0;
+ GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
+ tmpblob->op = blob->op;
+
+ nbwritten = 0;
+
+ for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+ nread > 0;
+ nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
+ GdaBinary *bin = (GdaBinary *) tmpblob;
+ glong tmp_written;
+ tmp_written = fwrite ((char *) (bin->data), 1, bin->binary_length, file);
+ if (tmp_written <= 0) {
+ gda_blob_free ((gpointer) tmpblob);
+ return -1;
+ }
+ nbwritten += tmp_written;
+ if (nread < buf_size)
+ /* nothing more to read */
+ break;
+ }
+ fclose (file);
+ gda_blob_free ((gpointer) tmpblob);
+ }
+ else {
+ bin = (GdaBinary *) blob;
+ nbwritten = fwrite ((char *) (bin->data), 1, bin->binary_length, file);
+ fclose (file);
+ }
return (nbwritten >= 0) ? nbwritten : -1;
}
Modified: trunk/libgda/gda-blob-op.c
==============================================================================
--- trunk/libgda/gda-blob-op.c (original)
+++ trunk/libgda/gda-blob-op.c Fri Nov 21 20:40:14 2008
@@ -92,10 +92,6 @@
/**
* gda_blob_op_get_length
* @op: an existing #GdaBlobOp
- *
- * Opens an existing BLOB. The BLOB must be initialized by
- * #gda_connection_create_blob or obtained from a #GValue.
- * FIXME: gda_connection_create_blob() no longer exists.
*
* Returns: the length of the blob in bytes. In case of error, -1 is returned and the
* provider should have added an error (a #GdaConnectionEvent) to the connection.
@@ -118,7 +114,7 @@
* @offset: offset to read from the start of the blob (starts at 0)
* @size: maximum number of bytes to read.
*
- * Reads a chunk of bytes from the BLOB into @blob.
+ * Reads a chunk of bytes from the BLOB accessible through @op into @blob.
*
* Returns: the number of bytes actually read. In case of error, -1 is returned and the
* provider should have added an error to the connection.
@@ -151,7 +147,10 @@
g_return_val_if_fail (blob, FALSE);
len = gda_blob_op_get_length (blob->op);
- return (gda_blob_op_read (blob->op, blob, 0, len) < 0) ? FALSE : TRUE;
+ if (len >= 0)
+ return (gda_blob_op_read (blob->op, blob, 0, len) < 0) ? FALSE : TRUE;
+ else
+ return FALSE;
}
/**
Modified: trunk/libgda/gda-column.c
==============================================================================
--- trunk/libgda/gda-column.c (original)
+++ trunk/libgda/gda-column.c Fri Nov 21 20:40:14 2008
@@ -577,7 +577,11 @@
* If there is already an attribute named @attribute set, then its value is replaced with the new @value,
* except if @value is %NULL, in which case the attribute is removed.
*
- * Warning: @sttribute should be a static string (no copy of it is made), so the string should exist as long as the @column
+ * Note: this method does not modify in any way the contents of the data model for which @column is a column (nor
+ * does it modify the table definition of the tables used by a SELECT statement is the model was created from a
+ * SELECT statement).
+ *
+ * Warning: @attribute should be a static string (no copy of it is made), so the string should exist as long as the @column
* object exists.
*/
void
Modified: trunk/libgda/gda-value.c
==============================================================================
--- trunk/libgda/gda-value.c (original)
+++ trunk/libgda/gda-value.c Fri Nov 21 20:40:14 2008
@@ -38,6 +38,8 @@
#include <libgda/gda-util.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
+#define __GDA_INTERNAL__
+#include "dir-blob-op.h"
#define l_g_value_unset(val) G_STMT_START{ if (G_IS_VALUE (val)) g_value_unset (val); }G_STMT_END
#ifdef G_OS_WIN32
@@ -1114,7 +1116,7 @@
* @val: value to set for the new #GValue.
* @size: the size of the memory pool pointer to by @val.
*
- * Makes a new #GValue of type #GDA_TYPE_BLOB with value @val.
+ * Makes a new #GValue of type #GDA_TYPE_BLOB with the data contained by @val.
*
* Returns: the newly created #GValue.
*/
@@ -1122,20 +1124,44 @@
gda_value_new_blob (const guchar *val, glong size)
{
GValue *value;
- GdaBlob blob;
+ GdaBlob *blob;
GdaBinary *bin;
+ blob = g_new0 (GdaBlob, 1);
bin = (GdaBinary*)(&blob);
-
- /* We use the const on the function parameter to make this clearer,
- * but it would be awkward to keep the const in the struct.
- */
- bin->data = (guchar*)val;
+ bin->data = g_new (guchar, size);
+ memcpy ((gpointer) bin->data, (gpointer) val, size);
bin->binary_length = size;
- blob.op = NULL;
+ blob->op = NULL;
value = g_new0 (GValue, 1);
- gda_value_set_blob (value, &blob);
+ g_value_init (value, GDA_TYPE_BLOB);
+ g_value_take_boxed (value, blob);
+
+ return value;
+}
+
+/**
+ * gda_value_new_blob
+ * @val: value to set for the new #GValue.
+ * @size: the size of the memory pool pointer to by @val.
+ *
+ * Makes a new #GValue of type #GDA_TYPE_BLOB with the data contained by @val.
+ *
+ * Returns: the newly created #GValue.
+ */
+GValue *
+gda_value_new_blob_from_file (const gchar *filename)
+{
+ GValue *value;
+ GdaBlob *blob;
+
+ blob = g_new0 (GdaBlob, 1);
+ blob->op = gda_dir_blob_op_new (filename);
+
+ value = g_new0 (GValue, 1);
+ g_value_init (value, GDA_TYPE_BLOB);
+ g_value_take_boxed (value, blob);
return value;
}
Modified: trunk/libgda/gda-value.h
==============================================================================
--- trunk/libgda/gda-value.h (original)
+++ trunk/libgda/gda-value.h Fri Nov 21 20:40:14 2008
@@ -111,6 +111,7 @@
GValue *gda_value_new_binary (const guchar *val, glong size);
GValue *gda_value_new_blob (const guchar *val, glong size);
+GValue *gda_value_new_blob_from_file (const gchar *filename);
GValue *gda_value_new_timestamp_from_timet (time_t val);
GValue *gda_value_new_from_string (const gchar *as_string, GType type);
Modified: trunk/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-provider.c (original)
+++ trunk/libgda/sqlite/gda-sqlite-provider.c Fri Nov 21 20:40:14 2008
@@ -1653,7 +1653,7 @@
if (params)
g_object_unref (params);
- /* create a prepared statement */
+ /* create a prepared statement object */
ps = gda_sqlite_pstmt_new (sqlite_stmt);
gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
_GDA_PSTMT (ps)->param_ids = param_ids;
@@ -2036,6 +2036,7 @@
else if (G_VALUE_TYPE (value) == G_TYPE_UCHAR)
sqlite3_bind_int (ps->sqlite_stmt, i, g_value_get_uchar (value));
else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+ TO_IMPLEMENT; /* use sqlite3_bind_zeroblob () */
GdaBinary *bin = (GdaBinary *) gda_value_get_blob (value);
sqlite3_bind_blob (ps->sqlite_stmt, i,
bin->data, bin->binary_length, SQLITE_TRANSIENT);
Modified: trunk/providers/postgres/gda-postgres-blob-op.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-blob-op.c (original)
+++ trunk/providers/postgres/gda-postgres-blob-op.c Fri Nov 21 20:40:14 2008
@@ -124,10 +124,11 @@
use_svp = TRUE;
if (use_svp)
- gda_connection_add_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
+ use_svp = gda_connection_add_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
pgop->priv->fd = lo_open (get_pconn (pgop->priv->cnc), pgop->priv->blobid, INV_READ | INV_WRITE);
if (pgop->priv->fd < 0) {
+ _gda_postgres_make_error (pgop->priv->cnc, get_pconn (pgop->priv->cnc), NULL, NULL);
if (use_svp)
gda_connection_rollback_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
return FALSE;
@@ -138,6 +139,13 @@
}
static void
+blob_op_close (GdaPostgresBlobOp *pgop)
+{
+ lo_close (get_pconn (pgop->priv->cnc), pgop->priv->fd);
+ pgop->priv->fd = -1;
+}
+
+static void
gda_postgres_blob_op_finalize (GObject * object)
{
GdaPostgresBlobOp *pgop = (GdaPostgresBlobOp *) object;
@@ -178,7 +186,6 @@
pconn = get_pconn (cnc);
pgop->priv->blobid = atoi (sql_id);
pgop->priv->cnc = cnc;
- blob_op_open (pgop);
return GDA_BLOB_OP (pgop);
}
@@ -203,8 +210,6 @@
}
}
- if (!blob_op_open (pgop))
- return FALSE;
return TRUE;
}
@@ -235,12 +240,25 @@
g_return_if_fail (pgop->priv);
g_return_if_fail (sql_id);
- if (pgop->priv->fd >= 0) {
- lo_close (get_pconn (pgop->priv->cnc), pgop->priv->fd);
- pgop->priv->fd = 0;
- }
+ if (pgop->priv->fd >= 0)
+ blob_op_close (pgop);
pgop->priv->blobid = atoi (sql_id);
- blob_op_open (pgop);
+}
+
+static gboolean
+check_transaction_started (GdaConnection *cnc, gboolean *out_started)
+{
+ GdaTransactionStatus *trans;
+
+ trans = gda_connection_get_transaction_status (cnc);
+ if (!trans) {
+ if (!gda_connection_begin_transaction (cnc, NULL,
+ GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL))
+ return FALSE;
+ else
+ *out_started = TRUE;
+ }
+ return TRUE;
}
/*
@@ -252,20 +270,39 @@
GdaPostgresBlobOp *pgop;
PGconn *pconn;
int pos;
+ gboolean transaction_started = FALSE;
g_return_val_if_fail (GDA_IS_POSTGRES_BLOB_OP (op), -1);
pgop = GDA_POSTGRES_BLOB_OP (op);
g_return_val_if_fail (pgop->priv, -1);
g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+
+ if (! check_transaction_started (pgop->priv->cnc, &transaction_started))
+ return -1;
if (!blob_op_open (pgop))
- return -1;
+ goto out_error;
+
pconn = get_pconn (pgop->priv->cnc);
pos = lo_lseek (pconn, pgop->priv->fd, 0, SEEK_END);
- if (pos < 0)
- return -1;
- else
- return pos;
+
+ if (pos < 0) {
+ _gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
+ goto out_error;
+ }
+
+ blob_op_close (pgop);
+ if (transaction_started)
+ gda_connection_rollback_transaction (pgop->priv->cnc, NULL, NULL);
+
+ return pos;
+
+ out_error:
+ blob_op_close (pgop);
+ if (transaction_started)
+ gda_connection_rollback_transaction (pgop->priv->cnc, NULL, NULL);
+
+ return -1;
}
static glong
@@ -274,6 +311,7 @@
GdaPostgresBlobOp *pgop;
PGconn *pconn;
GdaBinary *bin;
+ gboolean transaction_started = FALSE;
g_return_val_if_fail (GDA_IS_POSTGRES_BLOB_OP (op), -1);
pgop = GDA_POSTGRES_BLOB_OP (op);
@@ -283,13 +321,16 @@
return -1;
g_return_val_if_fail (blob, -1);
- if (!blob_op_open (pgop))
+ if (! check_transaction_started (pgop->priv->cnc, &transaction_started))
return -1;
+ if (!blob_op_open (pgop))
+ goto out_error;
+
pconn = get_pconn (pgop->priv->cnc);
if (lo_lseek (pconn, pgop->priv->fd, offset, SEEK_SET) < 0) {
_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
- return -1;
+ goto out_error;
}
bin = (GdaBinary *) blob;
@@ -297,7 +338,19 @@
g_free (bin->data);
bin->data = g_new0 (guchar, size);
bin->binary_length = lo_read (pconn, pgop->priv->fd, (char *) (bin->data), size);
+
+ blob_op_close (pgop);
+ if (transaction_started)
+ gda_connection_rollback_transaction (pgop->priv->cnc, NULL, NULL);
+
return bin->binary_length;
+
+ out_error:
+ blob_op_close (pgop);
+ if (transaction_started)
+ gda_connection_rollback_transaction (pgop->priv->cnc, NULL, NULL);
+
+ return -1;
}
static glong
@@ -305,8 +358,8 @@
{
GdaPostgresBlobOp *pgop;
PGconn *pconn;
- GdaBinary *bin;
glong nbwritten;
+ gboolean transaction_started = FALSE;
g_return_val_if_fail (GDA_IS_POSTGRES_BLOB_OP (op), -1);
pgop = GDA_POSTGRES_BLOB_OP (op);
@@ -314,21 +367,66 @@
g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
g_return_val_if_fail (blob, -1);
- if (!blob_op_open (pgop))
+ if (! check_transaction_started (pgop->priv->cnc, &transaction_started))
return -1;
+ if (!blob_op_open (pgop))
+ goto out_error;
+
pconn = get_pconn (pgop->priv->cnc);
if (lo_lseek (pconn, pgop->priv->fd, offset, SEEK_SET) < 0) {
_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
- return -1;
+ goto out_error;
}
- bin = (GdaBinary *) blob;
- nbwritten = lo_write (pconn, pgop->priv->fd, (char*) bin->data, bin->binary_length);
- if (nbwritten == -1) {
- _gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
- return -1;
+ if (blob->op && (blob->op != op)) {
+ /* use data through blob->op */
+ #define buf_size 16384
+ gint nread = 0;
+ GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
+ tmpblob->op = blob->op;
+
+ nbwritten = 0;
+
+ for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+ nread > 0;
+ nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
+ GdaBinary *bin = (GdaBinary *) tmpblob;
+ glong tmp_written;
+ tmp_written = lo_write (pconn, pgop->priv->fd, (char*) bin->data,
+ bin->binary_length);
+ if (tmp_written < 0) {
+ _gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
+ gda_blob_free ((gpointer) tmpblob);
+ goto out_error;
+ }
+ nbwritten += tmp_written;
+ if (nread < buf_size)
+ /* nothing more to read */
+ break;
+ }
+ gda_blob_free ((gpointer) tmpblob);
+ }
+ else {
+ /* use data in (GdaBinary *) blob */
+ GdaBinary *bin = (GdaBinary *) blob;
+ nbwritten = lo_write (pconn, pgop->priv->fd, (char*) bin->data, bin->binary_length);
+ if (nbwritten == -1) {
+ _gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
+ goto out_error;
+ }
}
+ blob_op_close (pgop);
+ if (transaction_started)
+ if (!gda_connection_commit_transaction (pgop->priv->cnc, NULL, NULL))
+ return -1;
+
return nbwritten;
+
+ out_error:
+ blob_op_close (pgop);
+ if (transaction_started)
+ gda_connection_rollback_transaction (pgop->priv->cnc, NULL, NULL);
+ return -1;
}
Modified: trunk/providers/postgres/gda-postgres-provider.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-provider.c (original)
+++ trunk/providers/postgres/gda-postgres-provider.c Fri Nov 21 20:40:14 2008
@@ -822,7 +822,7 @@
/*
* Get database request
*
- * Returns the server version as a string, which should be stored in @cnc's associated PostgresConnectionData structure
+ * Returns the database name as a string
*/
static const gchar *
gda_postgres_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
@@ -1084,7 +1084,7 @@
g_string_free (string, TRUE);
if (PQstatus (pconn) != CONNECTION_OK) {
- g_set_error (error, 0, 0, PQerrorMessage (pconn));
+ g_set_error (error, 0, 0, "%s", PQerrorMessage (pconn));
PQfinish(pconn);
return FALSE;
@@ -1098,7 +1098,7 @@
pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, sql);
g_free (sql);
if (!pg_res || PQresultStatus (pg_res) != PGRES_COMMAND_OK) {
- g_set_error (error, 0, 0, PQresultErrorMessage (pg_res));
+ g_set_error (error, 0, 0, "%s", PQresultErrorMessage (pg_res));
PQfinish (pconn);
return FALSE;
}
@@ -1256,6 +1256,7 @@
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+ g_return_val_if_fail (name && *name, FALSE);
cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
@@ -1268,13 +1269,9 @@
const gchar *remain;
parser = gda_server_provider_internal_get_parser (provider);
- if (name)
- str = g_strdup_printf ("SAVEPOINT %s", name);
- else
- str = (gchar *) name;
+ str = g_strdup_printf ("SAVEPOINT %s", name);
stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
- if (name)
- g_free (str);
+ g_free (str);
if (!stmt) {
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
@@ -1309,6 +1306,7 @@
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+ g_return_val_if_fail (name && *name, FALSE);
cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
@@ -1321,13 +1319,9 @@
const gchar *remain;
parser = gda_server_provider_internal_get_parser (provider);
- if (name)
- str = g_strdup_printf ("ROLLBACK TO SAVEPOINT %s", name);
- else
- str = (gchar *) name;
+ str = g_strdup_printf ("ROLLBACK TO SAVEPOINT %s", name);
stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
- if (name)
- g_free (str);
+ g_free (str);
if (!stmt) {
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
@@ -1362,6 +1356,7 @@
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+ g_return_val_if_fail (name && *name, FALSE);
cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
@@ -1374,13 +1369,9 @@
const gchar *remain;
parser = gda_server_provider_internal_get_parser (provider);
- if (name)
- str = g_strdup_printf ("DELETE SAVEPOINT %s", name);
- else
- str = (gchar *) name;
+ str = g_strdup_printf ("RELEASE SAVEPOINT %s", name);
stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
- if (name)
- g_free (str);
+ g_free (str);
if (!stmt) {
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
@@ -1497,8 +1488,8 @@
dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
if (!dh) {
dh = gda_handler_time_new ();
- gda_handler_time_set_sql_spec ((GdaHandlerTime *) dh, G_DATE_YEAR,
- G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
+ gda_handler_time_set_sql_spec ((GdaHandlerTime *) dh, G_DATE_YEAR,
+ G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
@@ -1625,6 +1616,7 @@
{
GdaPostgresPStmt *ps;
PostgresConnectionData *cdata;
+ static guint counter = 0; /* each prepared statement MUST have a unique name, ensured with this counter */
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1656,7 +1648,7 @@
gchar *prep_stm_name;
GdaConnectionEvent *event = NULL;
- prep_stm_name = g_strdup_printf ("ps%p", stmt);
+ prep_stm_name = g_strdup_printf ("psc%d", counter ++);
pg_res = PQprepare (cdata->pconn, prep_stm_name, sql, 0, NULL);
if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
event = _gda_postgres_make_error (cnc, cdata->pconn, pg_res, error);
@@ -1698,6 +1690,7 @@
gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
g_object_unref (ps);
+
return TRUE;
out_err:
@@ -1710,15 +1703,19 @@
}
static gboolean
-check_transaction_started (GdaConnection *cnc)
+check_transaction_started (GdaConnection *cnc, gboolean *out_started)
{
GdaTransactionStatus *trans;
+
trans = gda_connection_get_transaction_status (cnc);
- if (!trans && !gda_connection_begin_transaction (cnc, NULL,
- GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL))
- return FALSE;
- else
- return TRUE;
+ if (!trans) {
+ if (!gda_connection_begin_transaction (cnc, NULL,
+ GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL))
+ return FALSE;
+ else
+ *out_started = TRUE;
+ }
+ return TRUE;
}
/*
@@ -1733,7 +1730,7 @@
gchar *prep_stm_name;
GdaConnectionEvent *event = NULL;
- prep_stm_name = g_strdup_printf ("ps%d", counter++);
+ prep_stm_name = g_strdup_printf ("pss%d", counter++);
pg_res = PQprepare (cdata->pconn, prep_stm_name, sql, 0, NULL);
if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
event = _gda_postgres_make_error (cdata->cnc, cdata->pconn, pg_res, error);
@@ -2007,7 +2004,7 @@
sql = gda_postgres_provider_statement_to_sql (provider, cnc, stmt, params, 0, NULL, error);
if (!sql)
return NULL;
- ps = prepare_stmt_simple (cdata, sql, error);
+ ps = prepare_stmt_simple (cdata, sql, error); // FIXME: this @ps is leaked!
g_free (sql);
if (!ps)
return NULL;
@@ -2025,6 +2022,7 @@
int *param_lengths = NULL;
int *param_formats = NULL;
gint nb_params;
+ gboolean transaction_started = FALSE;
nb_params = g_slist_length (_GDA_PSTMT (ps)->param_ids);
param_values = g_new0 (char *, nb_params + 1);
@@ -2060,7 +2058,7 @@
event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
gda_connection_event_set_description (event, str);
g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
- GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, str);
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
g_free (str);
break;
}
@@ -2078,7 +2076,7 @@
event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
gda_connection_event_set_description (event, str);
g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
- GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, str);
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
g_free (str);
break;
}
@@ -2100,7 +2098,7 @@
GdaPostgresBlobOp *op;
/* Postgres requires that a transaction be started for LOB operations */
- if (!check_transaction_started (cnc)) {
+ if (!check_transaction_started (cnc, &transaction_started)) {
event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
gda_connection_event_set_description (event, _("Cannot start transaction"));
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
@@ -2152,6 +2150,8 @@
g_strfreev (param_values);
g_free (param_lengths);
g_free (param_formats);
+ if (transaction_started)
+ gda_connection_rollback_transaction (cnc, NULL, NULL);
return NULL;
}
@@ -2168,12 +2168,18 @@
GdaStatement *estmt;
gchar *esql;
estmt = gda_select_alter_select_for_empty (stmt, error);
- if (!estmt)
+ if (!estmt) {
+ if (transaction_started)
+ gda_connection_rollback_transaction (cnc, NULL, NULL);
return NULL;
+ }
esql = gda_statement_to_sql (estmt, NULL, error);
g_object_unref (estmt);
- if (!esql)
+ if (!esql) {
+ if (transaction_started)
+ gda_connection_rollback_transaction (cnc, NULL, NULL);
return NULL;
+ }
pg_res = PQexec (cdata->pconn, esql);
g_free (esql);
@@ -2226,6 +2232,9 @@
}
gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
+ if (transaction_started)
+ gda_connection_commit_transaction (cnc, NULL, NULL);
+
return retval;
}
Modified: trunk/providers/postgres/gda-postgres-recordset.h
==============================================================================
--- trunk/providers/postgres/gda-postgres-recordset.h (original)
+++ trunk/providers/postgres/gda-postgres-recordset.h Fri Nov 21 20:40:14 2008
@@ -41,7 +41,7 @@
struct _GdaPostgresRecordset {
GdaDataSelect model;
- GdaPostgresRecordsetPrivate *priv;
+ GdaPostgresRecordsetPrivate *priv;
};
struct _GdaPostgresRecordsetClass {
Modified: trunk/providers/skel-implementation/capi/gda-capi-blob-op.c
==============================================================================
--- trunk/providers/skel-implementation/capi/gda-capi-blob-op.c (original)
+++ trunk/providers/skel-implementation/capi/gda-capi-blob-op.c Fri Nov 21 20:40:14 2008
@@ -100,15 +100,15 @@
static void
gda_capi_blob_op_finalize (GObject * object)
{
- GdaCapiBlobOp *pgop = (GdaCapiBlobOp *) object;
+ GdaCapiBlobOp *bop = (GdaCapiBlobOp *) object;
- g_return_if_fail (GDA_IS_CAPI_BLOB_OP (pgop));
+ g_return_if_fail (GDA_IS_CAPI_BLOB_OP (bop));
/* free specific information */
TO_IMPLEMENT;
- g_free (pgop->priv);
- pgop->priv = NULL;
+ g_free (bop->priv);
+ bop->priv = NULL;
parent_class->finalize (object);
}
@@ -116,14 +116,14 @@
GdaBlobOp *
gda_capi_blob_op_new (GdaConnection *cnc)
{
- GdaCapiBlobOp *pgop;
+ GdaCapiBlobOp *bop;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- pgop = g_object_new (GDA_TYPE_CAPI_BLOB_OP, NULL);
- pgop->priv->cnc = cnc;
+ bop = g_object_new (GDA_TYPE_CAPI_BLOB_OP, NULL);
+ bop->priv->cnc = cnc;
- return GDA_BLOB_OP (pgop);
+ return GDA_BLOB_OP (bop);
}
/*
@@ -132,12 +132,12 @@
static glong
gda_capi_blob_op_get_length (GdaBlobOp *op)
{
- GdaCapiBlobOp *pgop;
+ GdaCapiBlobOp *bop;
g_return_val_if_fail (GDA_IS_CAPI_BLOB_OP (op), -1);
- pgop = GDA_CAPI_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
- g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+ bop = GDA_CAPI_BLOB_OP (op);
+ g_return_val_if_fail (bop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
TO_IMPLEMENT;
return -1;
@@ -149,13 +149,13 @@
static glong
gda_capi_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
{
- GdaCapiBlobOp *pgop;
+ GdaCapiBlobOp *bop;
GdaBinary *bin;
g_return_val_if_fail (GDA_IS_CAPI_BLOB_OP (op), -1);
- pgop = GDA_CAPI_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
- g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+ bop = GDA_CAPI_BLOB_OP (op);
+ g_return_val_if_fail (bop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
if (offset >= G_MAXINT)
return -1;
g_return_val_if_fail (blob, -1);
@@ -178,18 +178,49 @@
static glong
gda_capi_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
{
- GdaCapiBlobOp *pgop;
+ GdaCapiBlobOp *bop;
GdaBinary *bin;
+ glong nbwritten = -1;
g_return_val_if_fail (GDA_IS_CAPI_BLOB_OP (op), -1);
- pgop = GDA_CAPI_BLOB_OP (op);
- g_return_val_if_fail (pgop->priv, -1);
- g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+ bop = GDA_CAPI_BLOB_OP (op);
+ g_return_val_if_fail (bop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
g_return_val_if_fail (blob, -1);
- /* write blob using bin->data and bin->binary_length */
- bin = (GdaBinary *) blob;
- TO_IMPLEMENT;
+ if (blob->op && (blob->op != op)) {
+ /* use data through blob->op */
+ #define buf_size 16384
+ gint nread = 0;
+ GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
+ tmpblob->op = blob->op;
+
+ nbwritten = 0;
+
+ for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+ nread > 0;
+ nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
+ glong tmp_written;
+
+ tmp_written = -1; TO_IMPLEMENT;
+
+ if (tmp_written < 0) {
+ /* treat error */
+ gda_blob_free ((gpointer) tmpblob);
+ return -1;
+ }
+ nbwritten += tmp_written;
+ if (nread < buf_size)
+ /* nothing more to read */
+ break;
+ }
+ gda_blob_free ((gpointer) tmpblob);
+ }
+ else {
+ /* write blob using bin->data and bin->binary_length */
+ bin = (GdaBinary *) blob;
+ nbwritten = -1; TO_IMPLEMENT;
+ }
- return -1;
+ return nbwritten;
}
Modified: trunk/providers/skel-implementation/capi/gda-capi-provider.c
==============================================================================
--- trunk/providers/skel-implementation/capi/gda-capi-provider.c (original)
+++ trunk/providers/skel-implementation/capi/gda-capi-provider.c Fri Nov 21 20:40:14 2008
@@ -418,7 +418,7 @@
/*
* Get database request
*
- * Returns the server version as a string, which should be stored in @cnc's associated CapiConnectionData structure
+ * Returns the database name as a string, which should be stored in @cnc's associated CapiConnectionData structure
*/
static const gchar *
gda_capi_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
@@ -908,6 +908,7 @@
GdaStatement *stmt, GError **error)
{
GdaCapiPStmt *ps;
+ gboolean retval = FALSE;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -918,15 +919,58 @@
if (ps)
return TRUE;
+ /* render as SQL understood by the provider */
+ GdaSet *params = NULL;
+ gchar *sql;
+ GSList *used_params = NULL;
+ if (! gda_statement_get_parameters (stmt, ¶ms, error))
+ return FALSE;
+ sql = gda_capi_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
+ &used_params, error);
+ if (!sql)
+ goto out;
+
/* prepare @stmt using the C API, creates @ps */
TO_IMPLEMENT;
- if (!ps)
- return FALSE;
- else {
- gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
- g_object_unref (ps);
- return TRUE;
- }
+
+ /* make a list of the parameter names used in the statement */
+ GSList *param_ids = NULL;
+ if (used_params) {
+ GSList *list;
+ for (list = used_params; list; list = list->next) {
+ const gchar *cid;
+ cid = gda_holder_get_id (GDA_HOLDER (list->data));
+ if (cid) {
+ param_ids = g_slist_append (param_ids, g_strdup (cid));
+ /*g_print ("PREPARATION: param ID: %s\n", cid);*/
+ }
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+ _("Unnamed parameter is not allowed in prepared statements"));
+ g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+ g_slist_free (param_ids);
+ goto out;
+ }
+ }
+ }
+
+ /* create a prepared statement object */
+ /*ps = gda_capi_pstmt_new (...);*/
+ gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
+ _GDA_PSTMT (ps)->param_ids = param_ids;
+ _GDA_PSTMT (ps)->sql = sql;
+
+ gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
+ g_object_unref (ps);
+
+ retval = TRUE;
+
+ out:
+ if (used_params)
+ g_slist_free (used_params);
+ if (params)
+ g_object_unref (params);
+ return retval;
}
/*
@@ -964,7 +1008,7 @@
if (async_cb) {
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
_("Provider does not support asynchronous statement execution"));
- return FALSE;
+ return NULL;
}
if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
@@ -991,13 +1035,20 @@
* where the C API cannot allow them (for example if the variable is the table name
* in a SELECT statement). The action here is to get the actual SQL code for @stmt,
* and use that SQL instead of @stmt to create another GdaCapiPStmt object.
+ *
+ * Don't call gda_connection_add_prepared_statement() with this new prepared statement
+ * as it will be destroyed once used.
*/
TO_IMPLEMENT;
return NULL;
}
- else
+ else {
ps = (GdaCapiPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
+ g_object_ref (ps);
+ }
}
+ else
+ g_object_ref (ps);
g_assert (ps);
/* optionnally reset the prepared statement if required by the API */
@@ -1074,6 +1125,7 @@
if (event) {
gda_connection_add_event (cnc, event);
+ g_object_unref (ps);
return NULL;
}
@@ -1091,12 +1143,16 @@
GdaStatement *estmt;
gchar *esql;
estmt = gda_select_alter_select_for_empty (stmt, error);
- if (!estmt)
+ if (!estmt) {
+ g_object_unref (ps);
return NULL;
+ }
esql = gda_statement_to_sql (estmt, NULL, error);
g_object_unref (estmt);
- if (!esql)
+ if (!esql) {
+ g_object_unref (ps);
return NULL;
+ }
/* Execute the 'esql' SQL code */
g_free (esql);
@@ -1121,6 +1177,7 @@
data_model = (GObject *) gda_capi_recordset_new (cnc, ps, params, flags, col_types);
gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
+ g_object_unref (ps);
return data_model;
}
else {
@@ -1131,6 +1188,7 @@
/* Create GdaConnectionEvent notice with the type of command and impacted rows */
gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
+ g_object_unref (ps);
return (GObject*) set;
}
}
Modified: trunk/tools/gda-sql.c
==============================================================================
--- trunk/tools/gda-sql.c (original)
+++ trunk/tools/gda-sql.c Fri Nov 21 20:40:14 2008
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <libgda/gda-quark-list.h>
#include <libgda/gda-meta-struct.h>
+#include <libgda/gda-blob-op.h>
#ifndef G_OS_WIN32
#include <signal.h>
@@ -53,6 +54,7 @@
gchar *single_command = NULL;
gchar *commandsfile = NULL;
+gboolean interractive = FALSE;
gboolean list_configs = FALSE;
gboolean list_providers = FALSE;
@@ -65,7 +67,8 @@
{ "output-file", 'o', 0, G_OPTION_ARG_STRING, &outfile, "Output file", "output file"},
{ "command", 'C', 0, G_OPTION_ARG_STRING, &single_command, "Run only single command (SQL or internal) and exit", "command" },
- { "commands-file", 'f', 0, G_OPTION_ARG_STRING, &commandsfile, "Execute commands from file, then exit", "filename" },
+ { "commands-file", 'f', 0, G_OPTION_ARG_STRING, &commandsfile, "Execute commands from file, then exit (except if -i specified)", "filename" },
+ { "interractive", 'i', 0, G_OPTION_ARG_NONE, &interractive, "Keep the console opened after executing a file (-f option)", NULL },
{ "list-dsn", 'l', 0, G_OPTION_ARG_NONE, &list_configs, "List configured data sources and exit", NULL },
{ "list-providers", 'L', 0, G_OPTION_ARG_NONE, &list_providers, "List installed database providers and exit", NULL },
{ NULL }
@@ -137,7 +140,7 @@
/* commands manipulation */
static GdaInternalCommandsList *build_internal_commands_list (MainData *data);
static gboolean command_is_complete (const gchar *command);
-static GdaInternalCommandResult *command_execute (MainData *data, gchar *command, GError **error);
+static GdaInternalCommandResult *command_execute (MainData *data, const gchar *command, GError **error);
static void display_result (MainData *data, GdaInternalCommandResult *res);
int
@@ -557,7 +560,7 @@
compute_prompt (data, prompt, data->partial_command == NULL ? FALSE : TRUE);
if (data->input_stream) {
cmde = input_from_stream (data->input_stream);
- if (!cmde && isatty (fileno (stdin))) {
+ if (interractive && !cmde && isatty (fileno (stdin))) {
/* go back to console after file is over */
set_input_file (data, NULL, NULL);
cmde = input_from_console (prompt->str);
@@ -579,10 +582,16 @@
{
if (!command || !(*command))
return FALSE;
+ if (single_command)
+ return TRUE;
if ((*command == '\\') || (*command == '.')) {
/* internal command */
return TRUE;
}
+ else if (*command == '#') {
+ /* comment, to be ignored */
+ return TRUE;
+ }
else {
if (command [strlen (command) - 1] == ';')
return TRUE;
@@ -597,31 +606,38 @@
*/
static GdaInternalCommandResult *execute_external_command (MainData *data, const gchar *command, GError **error);
static GdaInternalCommandResult *
-command_execute (MainData *data, gchar *command, GError **error)
+command_execute (MainData *data, const gchar *command, GError **error)
{
if (!command || !(*command))
- return NULL;
- if ((*command == '\\') || (*command == '.')) {
- if (data->current)
- return gda_internal_command_execute (data->internal_commands,
- data->current->cnc, command, error);
- else
- return gda_internal_command_execute (data->internal_commands, NULL, command, error);
- }
- else {
- if (!data->current) {
- g_set_error (error, 0, 0,
- _("No connection specified"));
- return NULL;
- }
- if (!gda_connection_is_opened (data->current->cnc)) {
- g_set_error (error, 0, 0,
- _("Connection closed"));
- return NULL;
- }
-
- return execute_external_command (data, command, error);
+ return NULL;
+ if ((*command == '\\') || (*command == '.')) {
+ if (data->current)
+ return gda_internal_command_execute (data->internal_commands,
+ data->current->cnc, command, error);
+ else
+ return gda_internal_command_execute (data->internal_commands, NULL, command, error);
+ }
+ else if (*command == '#') {
+ /* nothing to do */
+ GdaInternalCommandResult *res;
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ return res;
}
+ else {
+ if (!data->current) {
+ g_set_error (error, 0, 0,
+ _("No connection specified"));
+ return NULL;
+ }
+ if (!gda_connection_is_opened (data->current->cnc)) {
+ g_set_error (error, 0, 0,
+ _("Connection closed"));
+ return NULL;
+ }
+
+ return execute_external_command (data, command, error);
+ }
}
/*
@@ -677,26 +693,44 @@
GdaHolder *h = GDA_HOLDER (list->data);
GdaHolder *h_in_data = g_hash_table_lookup (data->parameters, gda_holder_get_id (h));
if (h_in_data) {
- gchar *str;
const GValue *cvalue;
GValue *value;
- GdaDataHandler *dh;
- GdaServerProvider *prov;
- prov = gda_connection_get_provider (data->current->cnc);
cvalue = gda_holder_get_value (h_in_data);
- dh = gda_server_provider_get_data_handler_g_type (prov, data->current->cnc,
- gda_holder_get_g_type (h_in_data));
- str = gda_data_handler_get_str_from_value (dh, cvalue);
-
- dh = gda_server_provider_get_data_handler_g_type (prov, data->current->cnc,
- gda_holder_get_g_type (h));
- value = gda_data_handler_get_value_from_str (dh, str, gda_holder_get_g_type (h));
- g_free (str);
- if (! gda_holder_take_value (h, value, error)) {
- g_free (res);
- res = NULL;
- goto cleanup;
+ if (cvalue && (G_VALUE_TYPE (cvalue) == gda_holder_get_g_type (h))) {
+ if (!gda_holder_set_value (h, cvalue, error)) {
+ g_free (res);
+ res = NULL;
+ goto cleanup;
+ }
+ }
+ else if (cvalue && (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL)) {
+ if (!gda_holder_set_value (h, cvalue, error)) {
+ g_free (res);
+ res = NULL;
+ goto cleanup;
+ }
+ }
+ else {
+ gchar *str;
+ str = gda_value_stringify (cvalue);
+ value = gda_value_new_from_string (str, gda_holder_get_g_type (h));
+ g_free (str);
+ if (! value) {
+ g_set_error (error, 0, 0,
+ _("Could not interpret the '%s' parameter's value"),
+ gda_holder_get_id (h));
+ g_free (res);
+ res = NULL;
+ goto cleanup;
+ }
+ else if (! gda_holder_take_value (h, value, error)) {
+ gda_value_free (value);
+ g_free (res);
+ res = NULL;
+ goto cleanup;
+ }
+ g_free (str);
}
}
else {
@@ -1021,6 +1055,8 @@
cs->name = g_strdup_printf ("c%d", cncindex);
cncindex++;
cs->parser = gda_connection_create_parser (newcnc);
+ if (!cs->parser)
+ cs->parser = gda_sql_parser_new ();
cs->cnc = newcnc;
cs->query_buffer = NULL;
cs->threader = NULL;
@@ -1409,6 +1445,13 @@
static GdaInternalCommandResult *extra_command_graph (GdaConnection *cnc, const gchar **args,
GError **error, MainData *data);
+static GdaInternalCommandResult *extra_command_lo_update (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data);
+static GdaInternalCommandResult *extra_command_export (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data);
+static GdaInternalCommandResult *extra_command_set2 (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data);
+
static GdaInternalCommandsList *
build_internal_commands_list (MainData *data)
{
@@ -1759,8 +1802,8 @@
c = g_new0 (GdaInternalCommand, 1);
c->group = _("Query buffer");
- c->name = g_strdup_printf (_("%s NAME"), "unset");
- c->description = _("Unset (delete) internal parameter");
+ c->name = g_strdup_printf (_("%s [NAME]"), "unset");
+ c->description = _("Unset (delete) internal named parameter (or all parameters)");
c->args = NULL;
c->command_func = (GdaInternalCommandFunc) extra_command_unset;
c->user_data = data;
@@ -1779,6 +1822,41 @@
c->unquote_args = TRUE;
commands->commands = g_slist_prepend (commands->commands, c);
+ /*
+ c = g_new0 (GdaInternalCommand, 1);
+ c->group = _("Query buffer");
+ c->name = g_strdup_printf (_("%s FILE TABLE BLOB_COLUMN ROW_CONDITION"), "lo_update");
+ c->description = _("Import a blob into the database");
+ c->args = NULL;
+ c->command_func = (GdaInternalCommandFunc) extra_command_lo_update;
+ c->user_data = data;
+ c->arguments_delimiter_func = NULL;
+ c->unquote_args = TRUE;
+ commands->commands = g_slist_prepend (commands->commands, c);
+ */
+
+ c = g_new0 (GdaInternalCommand, 1);
+ c->group = _("Query buffer");
+ c->name = g_strdup_printf (_("%s [NAME|TABLE COLUMN ROW_CONDITION] FILE"), "export");
+ c->description = _("Export internal parameter or table's value to the FILE file");
+ c->args = NULL;
+ c->command_func = (GdaInternalCommandFunc) extra_command_export;
+ c->user_data = data;
+ c->arguments_delimiter_func = NULL;
+ c->unquote_args = TRUE;
+ commands->commands = g_slist_prepend (commands->commands, c);
+
+ c = g_new0 (GdaInternalCommand, 1);
+ c->group = _("Query buffer");
+ c->name = g_strdup_printf (_("%s NAME [FILE|TABLE COLUMN ROW_CONDITION]"), "setex");
+ c->description = _("Set internal parameter as the contents of the FILE file or from an existing table's value");
+ c->args = NULL;
+ c->command_func = (GdaInternalCommandFunc) extra_command_set2;
+ c->user_data = data;
+ c->arguments_delimiter_func = NULL;
+ c->unquote_args = TRUE;
+ commands->commands = g_slist_prepend (commands->commands, c);
+
/* comes last */
c = g_new0 (GdaInternalCommand, 1);
c->group = _("General");
@@ -2285,6 +2363,8 @@
ncs->cnc = gda_meta_store_get_internal_connection (store);
g_object_ref (ncs->cnc);
ncs->parser = gda_connection_create_parser (ncs->cnc);
+ if (!cs->parser)
+ cs->parser = gda_sql_parser_new ();
ncs->query_buffer = NULL;
ncs->threader = NULL;
ncs->meta_job_id = 0;
@@ -3155,6 +3235,264 @@
gda_value_free (value);
}
+static const GValue *
+get_table_value_at_cell (GdaConnection *cnc, GError **error, MainData *data,
+ const gchar *table, const gchar *column, const gchar *row_cond,
+ GdaDataModel **out_model_of_value)
+{
+ const GValue *retval = NULL;
+
+ *out_model_of_value = NULL;
+
+ /* prepare executed statement */
+ gchar *sql;
+ gchar *rtable, *rcolumn;
+
+ if (gda_sql_identifier_needs_quotes (table))
+ rtable = gda_sql_identifier_add_quotes (table);
+ else
+ rtable = g_strdup (table);
+ if (gda_sql_identifier_needs_quotes (column))
+ rcolumn = gda_sql_identifier_add_quotes (column);
+ else
+ rcolumn = g_strdup (column);
+ sql = g_strdup_printf ("SELECT %s FROM %s WHERE %s", rcolumn, rtable, row_cond);
+ g_free (rtable);
+ g_free (rcolumn);
+
+ GdaStatement *stmt;
+ const gchar *remain;
+ stmt = gda_sql_parser_parse_string (data->current->parser, sql, &remain, error);
+ if (!stmt) {
+ g_free (sql);
+ return NULL;
+ }
+ if (remain) {
+ g_set_error (error, 0, 0,
+ _("Wrong row condition"));
+ g_free (sql);
+ return NULL;
+ }
+ g_object_unref (stmt);
+
+ /* execute statement */
+ GdaInternalCommandResult *tmpres;
+ tmpres = execute_external_command (data, sql, error);
+ g_free (sql);
+ if (!tmpres)
+ return NULL;
+ gboolean errorset = FALSE;
+ if (tmpres->type == GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL) {
+ GdaDataModel *model;
+ model = tmpres->u.model;
+ if (gda_data_model_get_n_rows (model) == 1) {
+ retval = gda_data_model_get_value_at (model, 0, 0, error);
+ if (!retval)
+ errorset = TRUE;
+ else
+ *out_model_of_value = g_object_ref (model);
+ }
+ }
+ gda_internal_command_exec_result_free (tmpres);
+
+ if (!retval && !errorset)
+ g_set_error (error, 0, 0,
+ _("No unique row identified"));
+
+ return retval;
+}
+
+static GdaInternalCommandResult *
+extra_command_set2 (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data)
+{
+ GdaInternalCommandResult *res = NULL;
+ const gchar *pname = NULL;
+ const gchar *filename = NULL;
+ const gchar *table = NULL;
+ const gchar *column = NULL;
+ const gchar *row_cond = NULL;
+ gint whichargs = 0;
+
+ if (!cnc) {
+ g_set_error (error, 0, 0, _("No current connection"));
+ return NULL;
+ }
+
+ if (args[0] && *args[0]) {
+ pname = args[0];
+ if (args[1] && *args[1]) {
+ if (args[2] && *args[2]) {
+ table = args[1];
+ column = args[2];
+ if (args[3] && *args[3]) {
+ row_cond = args[3];
+ if (args [4]) {
+ g_set_error (error, 0, 0,
+ _("Too many arguments"));
+ return NULL;
+ }
+ whichargs = 1;
+ }
+ }
+ else {
+ filename = args[1];
+ whichargs = 2;
+ }
+ }
+ }
+
+ if (whichargs == 1) {
+ /* param from an existing blob */
+ const GValue *value;
+ GdaDataModel *model = NULL;
+ value = get_table_value_at_cell (cnc, error, data, table, column, row_cond, &model);
+ if (value) {
+ GdaHolder *param = g_hash_table_lookup (data->parameters, pname);
+ if (param)
+ g_hash_table_remove (data->parameters, pname);
+
+ param = gda_holder_new (G_VALUE_TYPE (value));
+ g_assert (gda_holder_set_value (param, value, NULL));
+ g_hash_table_insert (data->parameters, g_strdup (pname), param);
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ }
+ if (model)
+ g_object_unref (model);
+ }
+ else if (whichargs == 2) {
+ /* param from filename */
+ GdaHolder *param = g_hash_table_lookup (data->parameters, pname);
+ GValue *bvalue;
+ if (param)
+ g_hash_table_remove (data->parameters, pname);
+
+ param = gda_holder_new (GDA_TYPE_BLOB);
+ bvalue = gda_value_new_blob_from_file (filename);
+ g_assert (gda_holder_take_value (param, bvalue, NULL));
+ g_hash_table_insert (data->parameters, g_strdup (pname), param);
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ }
+ else
+ g_set_error (error, 0, 0,
+ _("Wrong number of arguments"));
+
+ return res;
+}
+
+static GdaInternalCommandResult *
+extra_command_export (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data)
+{
+ GdaInternalCommandResult *res = NULL;
+
+ const gchar *pname = NULL;
+ const gchar *table = NULL;
+ const gchar *column = NULL;
+ const gchar *filename = NULL;
+ const gchar *row_cond = NULL;
+ gint whichargs = 0;
+
+ if (!cnc) {
+ g_set_error (error, 0, 0, _("No current connection"));
+ return NULL;
+ }
+
+ if (args[0] && *args[0]) {
+ table = args[0];
+ pname = args[0];
+ if (args[1] && *args[1]) {
+ column = args[1];
+ filename = args[1];
+ if (args[2] && *args[2]) {
+ row_cond = args[2];
+ if (args[3] && *args[3]) {
+ filename = args[3];
+ if (args [4]) {
+ g_set_error (error, 0, 0,
+ _("Too many arguments"));
+ return NULL;
+ }
+ else
+ whichargs = 1;
+ }
+ }
+ else {
+ whichargs = 2;
+ }
+ }
+ }
+
+ const GValue *value = NULL;
+ GdaDataModel *model = NULL;
+
+ if (whichargs == 1)
+ value = get_table_value_at_cell (cnc, error, data, table, column, row_cond, &model);
+ else if (whichargs == 2) {
+ GdaHolder *param = g_hash_table_lookup (data->parameters, pname);
+ if (!pname)
+ g_set_error (error, 0, 0,
+ _("No parameter named '%s' defined"), pname);
+ else
+ value = gda_holder_get_value (param);
+ }
+ else
+ g_set_error (error, 0, 0,
+ _("Wrong number of arguments"));
+
+ if (value) {
+ /* to file through this blob */
+ gboolean done = FALSE;
+
+ if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+ GValue *vblob = gda_value_new_blob_from_file (filename);
+ GdaBlob *tblob = (GdaBlob*) gda_value_get_blob (vblob);
+ const GdaBlob *fblob = gda_value_get_blob (value);
+ if (gda_blob_op_write (tblob->op, (GdaBlob*) fblob, 0) < 0)
+ g_set_error (error, 0, 0,
+ _("Could not write file"));
+ else
+ done = TRUE;
+ gda_value_free (vblob);
+ }
+ else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
+ GValue *vblob = gda_value_new_blob_from_file (filename);
+ GdaBlob *tblob = (GdaBlob*) gda_value_get_blob (vblob);
+ GdaBlob *fblob = g_new0 (GdaBlob, 1);
+ const GdaBinary *fbin = gda_value_get_binary (value);
+ ((GdaBinary *) fblob)->data = fbin->data;
+ ((GdaBinary *) fblob)->binary_length = fbin->binary_length;
+ if (gda_blob_op_write (tblob->op, (GdaBlob*) fblob, 0) < 0)
+ g_set_error (error, 0, 0,
+ _("Could not write file"));
+ else
+ done = TRUE;
+ g_free (fblob);
+ gda_value_free (vblob);
+ }
+ else {
+ gchar *str;
+ str = gda_value_stringify (value);
+ if (g_file_set_contents (filename, str, -1, error))
+ done = TRUE;
+ g_free (str);
+ }
+
+ if (done) {
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ }
+ }
+ if (model)
+ g_object_unref (model);
+
+
+ return res;
+}
+
+
static GdaInternalCommandResult *
extra_command_unset (GdaConnection *cnc, const gchar **args,
GError **error, MainData *data)
@@ -3176,9 +3514,12 @@
g_set_error (error, 0, 0,
_("No parameter named '%s' defined"), pname);
}
- else
- g_set_error (error, 0, 0,
- _("Missing parameter's name"));
+ else {
+ g_hash_table_destroy (data->parameters);
+ data->parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ }
return res;
}
@@ -3293,6 +3634,114 @@
return NULL;
}
+#ifdef NONE
+static GdaInternalCommandResult *
+extra_command_lo_update (GdaConnection *cnc, const gchar **args,
+ GError **error, MainData *data)
+{
+ GdaInternalCommandResult *res;
+
+ const gchar *table = NULL;
+ const gchar *blob_col = NULL;
+ const gchar *filename = NULL;
+ const gchar *row_cond = NULL;
+
+ if (!cnc) {
+ g_set_error (error, 0, 0, _("No current connection"));
+ return NULL;
+ }
+
+ if (args[0] && *args[0]) {
+ filename = args[0];
+ if (args[1] && *args[1]) {
+ table = args[1];
+ if (args[2] && *args[2]) {
+ blob_col = args[2];
+ if (args[3] && *args[3]) {
+ row_cond = args[3];
+ if (args [4]) {
+ g_set_error (error, 0, 0,
+ _("Too many arguments"));
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+ if (!row_cond) {
+ g_set_error (error, 0, 0,
+ _("Missing arguments"));
+ return NULL;
+ }
+
+ g_print ("file: #%s#\n", filename);
+ g_print ("table: #%s#\n", table);
+ g_print ("col: #%s#\n", blob_col);
+ g_print ("cond: #%s#\n", row_cond);
+ TO_IMPLEMENT;
+
+ /* prepare executed statement */
+ gchar *sql;
+ gchar *rtable, *rblob_col;
+
+ if (gda_sql_identifier_needs_quotes (table))
+ rtable = gda_sql_identifier_add_quotes (table);
+ else
+ rtable = g_strdup (table);
+ if (gda_sql_identifier_needs_quotes (blob_col))
+ rblob_col = gda_sql_identifier_add_quotes (blob_col);
+ else
+ rblob_col = g_strdup (blob_col);
+ sql = g_strdup_printf ("UPDATE %s SET %s = ##blob::GdaBlob WHERE %s", rtable, rblob_col, row_cond);
+ g_free (rtable);
+ g_free (rblob_col);
+
+ GdaStatement *stmt;
+ const gchar *remain;
+ stmt = gda_sql_parser_parse_string (data->current->parser, sql, &remain, error);
+ g_free (sql);
+ if (!stmt)
+ return NULL;
+ if (remain) {
+ g_set_error (error, 0, 0,
+ _("Wrong row condition"));
+ return NULL;
+ }
+
+ /* prepare execution environment */
+ GdaSet *params;
+ GdaHolder *h;
+ GValue *blob;
+
+ if (!gda_statement_get_parameters (stmt, ¶ms, error)) {
+ g_object_unref (stmt);
+ return NULL;
+ }
+
+ h = gda_set_get_holder (params, "blob");
+ g_assert (h);
+ blob = gda_value_new_blob_from_file (filename);
+ if (!gda_holder_take_value (h, blob, error)) {
+ gda_value_free (blob);
+ g_object_unref (params);
+ g_object_unref (stmt);
+ return NULL;
+ }
+
+ /* execute statement */
+ gint nrows;
+ nrows = gda_connection_statement_execute_non_select (cnc, stmt, params, NULL, error);
+ g_object_unref (params);
+ g_object_unref (stmt);
+ if (nrows == -1)
+ return NULL;
+
+ res = g_new0 (GdaInternalCommandResult, 1);
+ res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
+ return res;
+}
+#endif
+
static gchar **
args_as_string_func (const gchar *str)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]