Make ecpg SQLSTATE-aware. Map existing SQLCODE assignments to SQLSTATEs,
authorPeter Eisentraut
Fri, 1 Aug 2003 13:53:36 +0000 (13:53 +0000)
committerPeter Eisentraut
Fri, 1 Aug 2003 13:53:36 +0000 (13:53 +0000)
rather than parsing the message.  Add some documentation about embedded
SQL.

15 files changed:
doc/src/sgml/ecpg.sgml
src/backend/commands/portalcmds.c
src/interfaces/ecpg/compatlib/Makefile
src/interfaces/ecpg/ecpglib/connect.c
src/interfaces/ecpg/ecpglib/data.c
src/interfaces/ecpg/ecpglib/descriptor.c
src/interfaces/ecpg/ecpglib/error.c
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/ecpglib/extern.h
src/interfaces/ecpg/ecpglib/memory.c
src/interfaces/ecpg/ecpglib/misc.c
src/interfaces/ecpg/ecpglib/prepare.c
src/interfaces/ecpg/include/ecpglib.h
src/interfaces/ecpg/include/sqlca.h
src/interfaces/ecpg/test/Makefile

index ee386339286f8598a5888f1e8601109db8de9352..7c4de83b30b5d2ea0043bcccdc82060d9306e836 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -37,15 +37,16 @@ $Header: /cvsroot/pgsql/doc/src/sgml/ecpg.sgml,v 1.46 2003/08/01 03:10:04 momjia
    Embedded SQL has advantages over other methods
    for handling SQL commands from C code. First, it
    takes care of the tedious passing of information to and from
-   variables in your C program.  Secondly, embedded
-   SQL in C is defined in the
-   SQL standard and supported by many other
-   SQL databases.  The PostgreSQL
-   implementation is designed to match this standard as much as
-   possible, and it is usually possible to port embedded
-   SQL programs written for other
-   SQL databases to PostgreSQL
-   with relative ease.
+   variables in your C program.  Second, the SQL
+   code in the program is checked at build time for syntactical
+   correctness.  Third, embedded SQL in C is
+   specified in the SQL standard and supported by
+   many other SQL database systems.  The
+   PostgreSQL implementation is designed to match this
+   standard as much as possible, and it is usually possible to port
+   embedded SQL programs written for other SQL
+   databases to PostgreSQL with relative
+   ease.
   
 
   
@@ -100,13 +101,13 @@ EXEC SQL CONNECT TO target AS 
  
     
      
-      character variable
+      an SQL string literal containing one of the above forms
      
     
 
     
      
-      character string
+      a reference to a character variable containing one of the above forms (see examples)
      
     
  
@@ -116,6 +117,16 @@ EXEC SQL CONNECT TO target AS 
      
     
    
+
+   If you specify the connection target literally (that is, not
+   through a variable reference) and you don't quote the value, then
+   the case-insensitivity rules of normal SQL are applied.  In that
+   case you can also double-quote the individual parameters separately
+   as needed.  In practice, it is probably less error-prone to use a
+   (single-quoted) string literal or a variable reference.  The
+   connection target DEFAULT initiates a connection
+   to the default database under the default user name.  No separate
+   user name or connection name may be specified in that case.
   
 
   
@@ -146,15 +157,47 @@ EXEC SQL CONNECT TO target AS 
      
     
    
-   The username and
-   password may be an SQL name, a
-   character variable, or a character string.
+
+   As above, the parameters username and
+   password may be an SQL identifier, an
+   SQL string literal, or a reference to a character variable.
   
 
   
    The connection-name is used to handle
    multiple connections in one program.  It can be omitted if a
-   program uses only one connection.
+   program uses only one connection.  The most recently opened
+   connection becomes the current connection, which is used by default
+   when an SQL statement is to be executed (see later in this
+   chapter).
+  
+
+  
+   Here are some examples of CONNECT statements:
+
+EXEC SQL CONNECT TO [email protected];
+
+EXEC SQL CONNECT TO 'unix:postgresql://sql.mydomain.com/mydb' AS myconnection USER john;
+
+EXEC SQL BEGIN DECLARE SECTION;
+const char *target = "[email protected]";
+const char *user = "john";
+EXEC SQL END DECLARE SECTION;
+ ...
+EXEC SQL CONNECT TO :target USER :user;
+
+   The last form makes use of the variant referred to above as
+   character variable reference.  You will see in later sections how C
+   variables can be used in SQL statements when you prefix them with a
+   colon.
+  
+
+  
+   Be advised that the format of the connection target is not
+   specified in the SQL standard.  So if you want to develop portable
+   applications, you might want to use something based on the last
+   example above to encapsulate the connection target string
+   somewhere.
   
  
 
@@ -194,6 +237,14 @@ EXEC SQL DISCONNECT connection;
      
     
    
+
+   If no connection name is specified, the current connection is
+   closed.
+  
+
+  
+   It is good style that an application always explicitly disconnect
+   from every connection it opened.
   
  
 
@@ -231,14 +282,14 @@ EXEC SQL COMMIT;
   
 
   
-   Singleton Select:
+   Single-row Select:
 
 EXEC SQL SELECT foo INTO :FooBar FROM table1 WHERE ascii = 'doodad';
 
   
 
   
-   Select using Cursors:
+   Select using cursors:
 
 EXEC SQL DECLARE foo_bar CURSOR FOR
     SELECT number, ascii FROM foo
@@ -264,8 +315,8 @@ EXEC SQL COMMIT;
    The tokens of the form
    :something are
    host variables, that is, they refer to
-   variables in the C program.  They are explained in the next
-   section.
+   variables in the C program.  They are explained in 
+   linkend="ecpg-variables">.
   
 
   
@@ -281,65 +332,512 @@ EXEC SQL COMMIT;
   
  
 
-  Passing Data
+  Choosing a Connection
+
+  
+   The SQL statements shown in the previous section are executed on
+   the current connection, that is, the most recently opened one.  If
+   an application needs to manage multiple connections, then there are
+   two ways to handle this.
+  
+
+  
+   The first option is to explicitly choose a connection for each SQL
+   statement, for example
+
+EXEC SQL AT connection-name SELECT ...;
+
+   This option is particularly suitable if the application needs to
+   use several connections in mixed order.
+  
 
   
-   To pass data from the program to the database, for example as
-   parameters in a query, or to pass data from the database back to
-   the program, the C variables that are intended to contain this data
-   need to be declared in a specially marked section, so the embedded
-   SQL preprocessor is made aware of them.
+   The second option is to execute a statement to switch the current
+   connection.  That statement is:
+
+SET CONNECTION connection-name;
+
+   This option is particularly convenient if many statements are to be
+   executed on the same connection.
   
+
+  Using Host Variables
 
   
-   This section starts with
+   In  you saw how you can execute SQL
+   statements from an embedded SQL program.  Some of those statements
+   only used fixed values and did not provide a way to insert
+   user-supplied values into statements or have the program process
+   the values returned by the query.  Those kinds of statements are
+   not really useful in real applications.  This section explains in
+   detail how you can pass data between your C program and the
+   embedded SQL statements using a simple mechanism called
+   host variables.
+  
+
+  
+   Overview
+
+   
+    Passing data between the C program and the SQL statements is
+    particularly simple in embedded SQL.  Instead of having the
+    program paste the data into the statement, which entails various
+    complications, such as properly quoting the value, you can simply
+    write the name of a C variable into the SQL statement, prefixed by
+    a colon.  For example:
+
+INSERT INTO sometable VALUES (:v1, 'foo', :v2);
+
+    This statements refers to two C variables named
+    v1 and v2 and also uses a
+    regular SQL string literal, to illustrate that you are not
+    restricted to use one kind of data or the other.
+   
+
+   
+    This style of inserting C variables in SQL statements works
+    anywhere a value expression is expected in an SQL statement.  In
+    the SQL environment we call the references to C variables
+    host variables.
+   
+  
+
+  
+   Declare Sections
+
+   
+    To pass data from the program to the database, for example as
+    parameters in a query, or to pass data from the database back to
+    the program, the C variables that are intended to contain this
+    data need to be declared in specially marked sections, so the
+    embedded SQL preprocessor is made aware of them.
+   
+
+   
+    This section starts with
 
 EXEC SQL BEGIN DECLARE SECTION;
 
-   and ends with
+    and ends with
 
 EXEC SQL END DECLARE SECTION;
 
-   Between those lines, there must be normal C variable declarations, such as
+    Between those lines, there must be normal C variable declarations,
+    such as
 
 int   x;
 char  foo[16], bar[16];
 
+    You can have as many declare sections in a program as you like.
+   
+
+   
+    The declarations are also echoed to the output file as a normal C
+    variables, so there's no need to declare them again.  Variables
+    that are not intended to be used with SQL commands can be declared
+    normally outside these special sections.
+   
+
+   
+    The definition of a structure or union also must be listed inside
+    a DECLARE section. Otherwise the preprocessor cannot
+    handle these types since it does not know the definition.
+   
+
+   
+    The special types VARCHAR and VARCHAR2
+    are converted into a named struct for every variable. A
+    declaration like
+
+VARCHAR var[180];
+
+    is converted into
+
+struct varchar_var { int len; char arr[180]; } var;
+
+    This structure is suitable for interfacing with SQL datums of type
+    varchar.
+   
+  
+
+  
+   <command>SELECT INTO</command> and <command>FETCH INTO</command>
+
+   
+    Now you should be able to pass data generated by your program into
+    an SQL command.  But how do you retrieve the results of a query?
+    For that purpose, embedded SQL provides special variants of the
+    usual commands SELECT and
+    FETCH.  These commands have a special
+    INTO clause that specifies which host variables
+    the retrieved values are to be stored in.
+   
+
+   
+    Here is an example:
+
+/*
+ * assume this table:
+ * CREATE TABLE test1 (a int, b varchar(50));
+ */
+
+EXEC SQL BEGIN DECLARE SECTION;
+int v1;
+VARCHAR v2;
+EXEC SQL END DECLARE SECTION;
+
+ ...
+
+EXEC SQL SELECT a, b INTO :v1, :v2 FROM test;
+
+    So the INTO clause appears between the select
+    list and the FROM clause.  The number of
+    elements in the select list and the list after
+    INTO (also called the target list) must be
+    equal.
+   
+
+   
+    Here is an example using the command FETCH:
+
+EXEC SQL BEGIN DECLARE SECTION;
+int v1;
+VARCHAR v2;
+EXEC SQL END DECLARE SECTION;
+
+ ...
+
+EXEC SQL DECLARE foo CURSOR FOR SELECT a, b FROM test;
+
+ ...
+
+do {
+    ...
+    EXEC SQL FETCH NEXT FROM foo INTO :v1, :v2;
+    ...
+} while (...);
+
+    Here the INTO clause appears after all the
+    normal clauses.
+   
+
+   
+    Both of these methods only allow retrieving one row at a time.  If
+    you need to process result sets that potentially contain more than
+    one row, you need to use a cursor, as shown in the second example.
+   
+  
+
+  
+   Indicators
+
+   
+    The examples above do not handle null values.  In fact, the
+    retrieval examples will raise an error if they fetch a null value
+    from the database.  To be able to pass null values to the database
+    or retrieve null values from the database, you need to append a
+    second host variable specification to each host variable that
+    contains data.  This second host variable is called the
+    indicator and contains a flag that tells
+    whether the datums is null, in which case the value of the real
+    host variable is ignored.  Here is an example that handles the
+    retrieval of null values correctly:
+
+EXEC SQL BEGIN DECLARE SECTION;
+VARCHAR val;
+int val_ind;
+EXEC SQL END DECLARE SECTION:
+
+ ...
+
+EXEC SQL SELECT b INTO :val :val_ind FROM test1;
+
+    The indicator variable val_ind will be zero if
+    the value was not null, and it will be negative if the value was
+    null.
+   
+
+   
+    The indicator has another function: if the indicator value is
+    positive, it means that the value is not null, but it was
+    truncated when it was stored in the host variable.
+   
+  
+
+  Dynamic SQL
+
+  
+   In many cases, the particular SQL statements that an application
+   has to execute are known at the time the application is written.
+   In some cases, however, the SQL statements are composed at run time
+   or provided by an external source.  In these cases you cannot embed
+   the SQL statements directly into the C source code, but there is a
+   facility that allows you to call arbitrary SQL statements that you
+   provide in a string variable.
   
 
   
-   The declarations are also echoed to the output file as a normal C
-   variables, so there's no need to declare them again.  Variables
-   that are not intended to be used with SQL commands can be declared
-   normally outside these special sections.
+   The simplest way to execute an arbitrary SQL statement is to use
+   the command EXECUTE IMMEDIATE.  For example:
+
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "CREATE TABLE test1 (...);";
+EXEC SQL END DECLARE SECTION;
+
+EXECUTE IMMEDIATE :stmt;
+
+   You may not execute statements that retrieve data (e.g.,
+   SELECT) this way.
   
 
   
-   The definition of a structure or union also must be listed inside a
-   DECLARE section. Otherwise the preprocessor cannot
-   handle these types since it does not know the definition.
+   A more powerful way to execute arbitrary SQL statements is to
+   prepare them once and execute the prepared statement as often as
+   you like.  It is also possible to prepare a generalized version of
+   a statement and then execute specific versions of it by
+   substituting parameters.  When preparing the statement, write
+   question marks where you want to substitute parameters later.  For
+   example:
+
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "INSERT INTO test1 VALUES(?, ?);";
+EXEC SQL END DECLARE SECTION;
+
+PREPARE mystmt FROM :stmt;
+ ...
+EXECUTE mystmt USING 42, 'foobar';
+
+   If the statement you are executing returns values, then add an
+   INTO clause:
+
+EXEC SQL BEGIN DECLARE SECTION;
+const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?";
+int v1, v2;
+VARCHAR v3;
+EXEC SQL END DECLARE SECTION;
+
+PREPARE mystmt FROM :stmt;
+ ...
+EXECUTE mystmt INTO v1, v2, v3 USING 37;
+
+   An EXECUTE command may have an
+   INTO clause, a USING clause,
+   both, or neither.
   
 
   
-   The special types VARCHAR and VARCHAR2
-   are converted into a named struct for every variable. A
-   declaration like
+   When you don't need the prepared statement anymore, you should
+   deallocate it:
 
-VARCHAR var[180];
+EXEC SQL DEALLOCATE PREPARE name;
 
-   is converted into
+  
+
+  Using SQL Descriptor Areas
+
+  
+   An SQL descriptor area is a more sophisticated method for
+   processing the result of a SELECT or
+   FETCH statement.  An SQL descriptor area groups
+   the data of one row of data together with metadata items into one
+   data structure.  The metadata is particularly useful when executing
+   dynamic SQL statements, where the nature of the result columns may
+   not be known ahead of time.
+  
+
+  
+   An SQL descriptor area consists of a header, which contains
+   information concerning the entire descriptor, and one or more item
+   descriptor areas, which basically each describe one column in the
+   result row.
+  
+
+  
+   Before you can use an SQL descriptor area, you need to allocate one:
 
-struct varchar_var { int len; char arr[180]; } var;
+EXEC SQL ALLOCATE DESCRIPTOR identifier;
+
+   The identifier serves as the variable name of the
+   descriptor area.  The scope of the allocated descriptor is WHAT?.
+   When you don't need the descriptor anymore, you should deallocate
+   it:
+
+EXEC SQL DEALLOCATE DESCRIPTOR identifier;
 
-   This structure is suitable for interfacing with SQL datums of type
-   varchar.
   
 
   
-   To use a properly declared C variable in an SQL statement, write
-   :varname where an expression is
-   expected.  See the previous section for some examples.
+   To use a descriptor area, specify it as the storage target in an
+   INTO clause, instead of listing host variables:
+
+EXEC SQL FETCH NEXT FROM mycursor INTO DESCRIPTOR mydesc;
+
+  
+
+  
+   Now how do you get the data out of the descriptor area?  You can
+   think of the descriptor area as a structure with named fields.  To
+   retrieve the value of a field from the header and store it into a
+   host variable, use the following command:
+
+EXEC SQL GET DESCRIPTOR name :hostvar = field;
+
+   Currently, there is only one header field defined:
+   COUNT, which tells how many item
+   descriptor areas exist (that is, how many columns are contained in
+   the result).  The host variable needs to be of an integer type.  To
+   get a field from the item descriptor area, use the following
+   command:
+
+EXEC SQL GET DESCRIPTOR name VALUE num :hostvar = field;
+
+   num can be a literal integer or a host
+   variable containing an integer. Possible fields are:
+
+   
+    
+     CARDINALITY (integer)
+     
+      
+       number of rows in the result set
+      
+     
+    
+
+    
+     DATA
+     
+      
+       actual data item (therefore, the data type of this field
+       depends on the query)
+      
+     
+    
+
+    
+     DATETIME_INTERVAL_CODE (integer)
+     
+      
+       ?
+      
+     
+    
+
+    
+     DATETIME_INTERVAL_PRECISION (integer)
+     
+      
+       not implemented
+      
+     
+    
+
+    
+     INDICATOR (integer)
+     
+      
+       the indicator (indicating a null value or a value truncation)
+      
+     
+    
+
+    
+     KEY_MEMBER (integer)
+     
+      
+       not implemented
+      
+     
+    
+
+    
+     LENGTH (integer)
+     
+      
+       length of the datum in characters
+      
+     
+    
+
+    
+     NAME (string)
+     
+      
+       name of the column
+      
+     
+    
+
+    
+     NULLABLE (integer)
+     
+      
+       not implemented
+      
+     
+    
+
+    
+     OCTET_LENGTH (integer)
+     
+      
+       length of the character representation of the datum in bytes
+      
+     
+    
+
+    
+     PRECISION (integer)
+     
+      
+       precision (for type numeric)
+      
+     
+    
+
+    
+     RETURNED_LENGTH (integer)
+     
+      
+       length of the datum in characters
+      
+     
+    
+
+    
+     RETURNED_OCTET_LENGTH (integer)
+     
+      
+       length of the character representation of the datum in bytes
+      
+     
+    
+
+    
+     SCALE (integer)
+     
+      
+       scale (for type numeric)
+      
+     
+    
+
+    
+     TYPE (integer)
+     
+      
+       numeric code of the data type of the column
+      
+     
+    
+   
   
  
 
@@ -347,35 +845,198 @@ struct varchar_var { int len; char arr[180]; } var;
   Error Handling
 
   
-   The embedded SQL interface provides a simplistic and a complex way
-   to handle exceptional conditions in a program.  The first method
-   causes a message to printed automatically when a certain condition
-   occurs.  For example:
+   This section describes how you can handle exceptional conditions
+   and warnings in an embedded SQL program.  There are several
+   nonexclusive facilities for this.
+  
+
+  
+   Setting Callbacks
+
+   
+    One simple method to catch errors and warnings is to set a
+    specific action to be executed whenever a particular condition
+    occurs.  In general:
 
-EXEC SQL WHENEVER sqlerror sqlprint;
+EXEC SQL WHENEVER condition action;
 
-   or
+   
+
+   
+    condition can be one of the following:
+
+    
+     
+      SQLERROR
+      
+       
+        The specified action is called whenever an error occurs during
+        the execution of an SQL statement.
+       
+      
+     
+
+     
+      SQLWARNING
+      
+       
+        The specified action is called whenever a warning occurs
+        during the execution of an SQL statement.
+       
+      
+     
+
+     
+      NOT FOUND
+      
+       
+        The specified action is called whenever an SQL statement
+        retrieves or affects zero rows.  (This condition is not an
+        error, but you might be interested in handling it specially.)
+       
+      
+     
+    
+   
+
+   
+    action can be one of the following:
+
+    
+     
+      CONTINUE
+      
+       
+        This effectively means that the condition is ignored.  This is
+        the default.
+       
+      
+     
+
+     
+      GOTO label
+      GO TO label
+      
+       
+        Jump to the specified label (using a C goto
+        statement).
+       
+      
+     
+
+     
+      SQLPRINT
+      
+       
+        Print a message to standard error.  This is useful for simple
+        programs or during prototyping.  The details of the message
+        cannot be configured.
+       
+      
+     
+
+     
+      STOP
+      
+       
+        Call exit(1), which will terminate the
+        program.
+       
+      
+     
+
+     
+      BREAK
+      
+       
+        Execute the C statement break.  This should
+        only be used in loops or switch statements.
+       
+      
+     
+
+     
+      CALL name (args)
+      DO name (args)
+      
+       
+        Call the specified C functions with the specified arguments.
+       
+      
+     
+    
+
+    The SQL standard only provides for the actions
+    CONTINUE and GOTO (and
+    GO TO).
+   
+
+   
+    Here is an example that you might want to use in a simple program.
+    It prints a simple message when a warning occurs and aborts the
+    program when an error happens.
 
-EXEC SQL WHENEVER not found sqlprint;
+EXEC SQL WHENEVER SQLWARNING SQLPRINT;
+EXEC SQL WHENEVER SQLERROR STOP;
 
-   This error handling remains enabled throughout the entire program.
-  
+   
 
-  
    
-    This is not an exhaustive example of usage
-    for the EXEC SQL WHENEVER statement.  Further
-    examples of usage may be found in SQL manuals (e.g.,
-    The LAN TIMES Guide to SQL by Groff and Weinberg).
+    The statement EXEC SQL WHENEVER is a directive
+    of the SQL preprocessor, not a C statement.  The error or warning
+    actions that it sets apply to all embedded SQL statements that
+    appear below the point where the handler is set, unless a
+    different action was set for the same condition between the first
+    EXEC SQL WHENEVER and the SQL statement causing
+    the condition, regardless of the flow of control in the C program.
+    So neither of the two following C program exerpts will have the
+    desired effect.
+
+/*
+ * WRONG
+ */
+int main(int argc, char *argv[])
+{
+    ...
+    if (verbose) {
+        EXEC SQL WHENEVER SQLWARNING SQLPRINT;
+    }
+    ...
+    EXEC SQL SELECT ...;
+    ...
+}
+
+
+
+/*
+ * WRONG
+ */
+int main(int argc, char *argv[])
+{
+    ...
+    set_error_handler();
+    ...
+    EXEC SQL SELECT ...;
+    ...
+}
+
+static void set_error_handler(void)
+{
+    EXEC SQL WHENEVER SQLERROR STOP;
+}
+
    
-  note>
+  sect2>
 
-  
-   For a more powerful error handling, the embedded SQL interface
-   provides a struct and a variable with the name
-   sqlca as follows:
+  
+   sqlca
+
+   
+    For a more powerful error handling, the embedded SQL interface
+    provides a global variable with the name sqlca
+    that has the following structure:
 
-struct sqlca
+struct
 {
     char sqlcaid[8];
     long sqlabc;
@@ -386,317 +1047,411 @@ struct sqlca
         char sqlerrmc[70];
     } sqlerrm;
     char sqlerrp[8];
-
     long sqlerrd[6];
-    /* 0: empty                                         */
-    /* 1: OID of processed row if applicable            */
-    /* 2: number of rows processed in an INSERT, UPDATE */
-    /*    or DELETE statement                           */
-    /* 3: empty                                         */
-    /* 4: empty                                         */
-    /* 5: empty                                         */
-
     char sqlwarn[8];
-    /* 0: set to 'W' if at least one other is 'W'       */
-    /* 1: if 'W' at least one character string          */
-    /*    value was truncated when it was               */
-    /*    stored into a host variable                   */
-    /* 2: empty                                         */
-    /* 3: empty                                         */
-    /* 4: empty                                         */
-    /* 5: empty                                         */
-    /* 6: empty                                         */
-    /* 7: empty                                         */
-
-    char sqlext[8];
+    char sqlstate[5];
 } sqlca;
 
-   (Many of the empty fields may be used in a future release.)
-  
+    (In a multithreaded program, every thread automatically gets its
+    own copy of sqlca.  This works similar to the
+    handling of the standard C global variable
+    errno.)
+   
 
-  
-   If no error occurred in the last SQL statement,
-   sqlca.sqlcode will be 0
-   (ECPG_NO_ERROR). If sqlca.sqlcode is
-   less than zero, this is a serious error, like the database
-   definition does not match the query. If it is greater than zero, it
-   is a normal error like the table did not contain the requested row.
-  
+   
+    sqlca covers both warnings and errors.  If
+    multiple warnings or errors occur during the execution of a
+    statement, then sqlca will only contain
+    information about the last one.
+   
 
-  
-   sqlca.sqlerrm.sqlerrmc will contain a string
-   that describes the error. The string ends with the line number in
-   the source file.
-  
+   
+    If no error occurred in the last SQL statement,
+    sqlca.sqlcode will be 0 and
+    sqlca.sqlstate will be
+    "00000".  If a warning or error occured, then
+    sqlca.sqlcode will be negative and
+    sqlca.sqlstate will be different from
+    "00000".  A positive
+    sqlca.sqlcode indicates a harmless condition,
+    such as that the last query returned zero rows.
+    sqlcode and sqlstate are two
+    different error code schemes; details appear below.
+   
 
-  
-   These are the errors that can occur:
+   
+    If the last SQL statement was successful, then
+    sqlca.sqlerrd[1] contains the OID of the
+    processed row, if applicable, and
+    sqlca.sqlerrd[2] contains the number of
+    processed or returned rows, if applicable to the command.
+   
 
-   
-    
-     -12: Out of memory in line %d.
-     
-      
-       Should not normally occur. This indicates your virtual memory
-       is exhausted.
+   
+    In case of an error or warning,
+    sqlca.sqlerrm.sqlerrmc will contain a string
+    that describes the error.  The field
+    sqlca.sqlerrm.sqlerrml contains the length of
+    the error message that is stored in
+    sqlca.sqlerrm.sqlerrmc (the result of
+    strlen(), not really interesting for a C
+    programmer).
+   
+
+   
+    In case of a warning, sqlca.sqlwarn[2] is set
+    to W.  (In all other cases, it is set to
+    something different from W.)  If
+    sqlca.sqlwarn[1] is set to
+    W, then a value was truncated when it was
+    stored in a host variable.  sqlca.sqlwarn[0] is
+    set to W if any of the other elements are set
+    to indicate a warning.
+   
+
+   
+    The fields sqlcaid,
+    sqlcabc,
+    sqlerrp, and the remaining elements of
+    sqlerrd and
+    sqlwarn currently contain no useful
+    information.
+   
+
+   
+    The structure sqlca is not defined in the SQL
+    standard, but is implemented in several other SQL database
+    systems.  The definitions are similar in the core, but if you want
+    to write portable applications, then you should investigate the
+    different implementations carefully.
+   
+  
+
+  
+   <literal>SQLSTATE</literal> vs <literal>SQLCODE</literal>
+
+   
+    The fields sqlca.sqlstate and
+    sqlca.sqlcode are two different schemes that
+    provide error codes.  Both are specified in the SQL standard, but
+    SQLCODE has been marked deprecated in the 1992
+    edition of the standard and has been dropped in the 1999 edition.
+    Therefore, new applications are strongly encouraged to use
+    SQLSTATE.
+   
+
+   
+    SQLSTATE is a five-character array.  The five
+    characters contain digits or upper-case letters that represent
+    codes of various error and warning conditions.
+    SQLSTATE has a hierarchical scheme: the first
+    two characters indicate the general class of the condition, the
+    last three characters indicate a subclass of the general
+    condition.  A successful state is indicated by the code
+    00000.  Further information about the codes can
+    be found XXX.  The SQLSTATE codes are for the
+    most part defined in the SQL standard.  The PostgreSQL server
+    natively supports SQLSTATE error codes;
+    therefore a high degree of consistency can be achieved by using
+    this error code scheme throughout all applications.
+   
+
+   
+    SQLCODE, the deprecated error code scheme, is a
+    simple integer.  A value of 0 indicates success, a positive value
+    indicates success with additional information, a negative value
+    indicates an error.  The SQL standard only defines the positive
+    value +100, which indicates that the last command returned or
+    affected zero rows, and no specific negative values.  Therefore,
+    this scheme can only achieve poor portability and does not have a
+    hierarchical code assignment.  Historically, the embedded SQL
+    processor for PostgreSQL has assigned some specific
+    SQLCODE values for its use, which are listed
+    below with their numeric value and their symbolic name.  Remember
+    that these are not portable to other SQL implementations.  To
+    simplify the porting of applications to the
+    SQLSTATE scheme, the corresponding
+    SQLSTATE is also listed.  There is, however, no
+    one-to-one or one-to-many mapping between the two schemes (indeed
+    it is many-to-many), so you should consult the global
+    SQLSTATE listing in XXX in each case.
+   
+
+   
+    These are the assigned SQLCODE values:
+
+    
+     
+      -12 (ECPG_OUT_OF_MEMORY)
+      
+       
+        Indicates that your virtual memory is exhausted. (SQLSTATE
+        YE001)
       
      
     
 
     
-     -200 (ECPG_UNSUPPORTED): Unsupported type %s on line %d.
+     -200 (ECPG_UNSUPPORTED)
      
       
-       Should not normally occur. This indicates the preprocessor has
-       generated something that the library does not know about.
-       Perhaps you are running incompatible versions of the
-       preprocessor and the library.
+       Indicates the preprocessor has generated something that the
+       library does not know about.  Perhaps you are running
+       incompatible versions of the preprocessor and the
+       library. (SQLSTATE YE002)
       
      
     
 
     
-     -201 (ECPG_TOO_MANY_ARGUMENTS): Too many arguments line %d.
+     -201 (ECPG_TOO_MANY_ARGUMENTS)
      
       
-       This means that the server has returned more arguments than we
-       have matching variables.  Perhaps you have forgotten a couple
-       of the host variables in the INTO
-       :var1, :var2 list.
+       This means that the command specified more host variables than
+       the command expected.  (SQLSTATE 07001 or 07002)
       
      
     
 
     
-     -202 (ECPG_TOO_FEW_ARGUMENTS): Too few arguments line %d.
+     -202 (ECPG_TOO_FEW_ARGUMENTS)
      
       
-       This means that the server has returned fewer arguments than we
-       have host variables. Perhaps you have too many host variables
-       in the INTO :var1,:var2 list.  
+       This means that the command specified fewer host variables than
+       the command expected.  (SQLSTATE 07001 or 07002)
+      
      
     
 
     
-     -203 (ECPG_TOO_MANY_MATCHES): Too many matches line %d.
+     -203 (ECPG_TOO_MANY_MATCHES)
      
       
-       This means the query has returned multiple rows but the
-       variables specified are not arrays. The
-       SELECT command was not unique.
+       This means a query has returned multiple rows but the statement
+       was only prepared to store one result row (for example, because
+       the specified variables are not arrays).  (SQLSTATE 21000)
       
      
     
 
     
-     -204 (ECPG_INT_FORMAT): Not correctly formatted int type: %s line %d.
+     -204 (ECPG_INT_FORMAT)
      
       
-       This means the host variable is of type int and
-       the field in the PostgreSQL database
-       is of another type and contains a value that cannot be
-       interpreted as an int. The library uses
-       strtol() for this conversion.
+       The host variable is of type int and the datum in
+       the database is of a different type and contains a value that
+       cannot be interpreted as an int.  The library uses
+       strtol() for this conversion.  (SQLSTATE
+       42804)
       
      
     
 
     
-     -205 (ECPG_UINT_FORMAT): Not correctly formatted unsigned type: %s line %d.
+     -205 (ECPG_UINT_FORMAT)
      
       
-       This means the host variable is of type unsigned
-       int and the field in the
-       PostgreSQL database is of another
-       type and contains a value that cannot be interpreted as an
-       unsigned int. The library uses
-       strtoul() for this conversion.
+       The host variable is of type unsigned int and the
+       datum in the database is of a different type and contains a
+       value that cannot be interpreted as an unsigned
+       int.  The library uses strtoul()
+       for this conversion.  (SQLSTATE 42804)
       
      
     
 
     
-     -206 (ECPG_FLOAT_FORMAT): Not correctly formatted floating-point type: %s line %d.
+     -206 (ECPG_FLOAT_FORMAT)
      
       
-       This means the host variable is of type float and
-       the field in the PostgreSQL database
-       is of another type and contains a value that cannot be
-       interpreted as a float. The library uses
-       strtod() for this conversion.
+       The host variable is of type float and the datum
+       in the database is of another type and contains a value that
+       cannot be interpreted as a float.  The library
+       uses strtod() for this conversion.
+       (SQLSTATE 42804)
       
      
     
 
     
-     -207 (ECPG_CONVERT_BOOL): Unable to convert %s to bool on line %d.
+     -207 (ECPG_CONVERT_BOOL)
      
       
        This means the host variable is of type bool and
-       the field in the PostgreSQL database
-       is neither 't' nor 'f'.
+       the datum in the database is neither 't' nor
+       'f'.  (SQLSTATE 42804)
       
      
     
 
     
-     -208 (ECPG_EMPTY): Empty query line %d.
+     -208 (ECPG_EMPTY)
      
       
-       The query was empty.  (This cannot normally happen in an
-       embedded SQL program, so it may point to an internal error.)
+       The statement sent to the PostgreSQL server was empty.  (This
+       cannot normally happen in an embedded SQL program, so it may
+       point to an internal error.)  (SQLSTATE YE002)
       
      
     
 
     
-     -209 (ECPG_MISSING_INDICATOR): NULL value without indicator in line %d.
+     -209 (ECPG_MISSING_INDICATOR)
      
       
        A null value was returned and no null indicator variable was
-       supplied.
+       supplied.  (SQLSTATE 22002)
       
      
     
 
     
-     -210 (ECPG_NO_ARRAY): Variable is not an array in line %d.
+     -210 (ECPG_NO_ARRAY)
      
       
        An ordinary variable was used in a place that requires an
-       array.
+       array.  (SQLSTATE 42804)
       
      
     
 
     
-     -211 (ECPG_DATA_NOT_ARRAY): Data read from backend is not an array in line %d.
+     -211 (ECPG_DATA_NOT_ARRAY)
      
       
        The database returned an ordinary variable in a place that
-       requires array value.
+       requires array value.  (SQLSTATE 42804)
       
      
     
 
     
-     -220 (ECPG_NO_CONN): No such connection %s in line %d.
+     -220 (ECPG_NO_CONN)
      
       
        The program tried to access a connection that does not exist.
+       (SQLSTATE 08003)
       
      
     
 
     
-     -221 (ECPG_NOT_CONN): Not connected in line %d.
+     -221 (ECPG_NOT_CONN)
      
       
        The program tried to access a connection that does exist but is
-       not open.
+       not open.  (This is an internal error.)  (SQLSTATE YE002)
       
      
     
 
     
-     -230 (ECPG_INVALID_STMT): Invalid statement name %s in line %d.
+     -230 (ECPG_INVALID_STMT)
      
       
        The statement you are trying to use has not been prepared.
+       (SQLSTATE 26000)
       
      
     
 
     
-     -240 (ECPG_UNKNOWN_DESCRIPTOR): Descriptor %s not found in line %d.
+     -240 (ECPG_UNKNOWN_DESCRIPTOR)
      
       
-       The descriptor specified was not found. The statement you are
-       trying to use has not been prepared.
+       The descriptor specified was not found.  The statement you are
+       trying to use has not been prepared.  (SQLSTATE 33000)
       
      
     
 
     
-     -241 (ECPG_INVALID_DESCRIPTOR_INDEX): Descriptor index out of range in line %d.
+     -241 (ECPG_INVALID_DESCRIPTOR_INDEX)
      
       
-       The descriptor index specified was out of range.
+       The descriptor index specified was out of range.  (SQLSTATE
+       07009)
       
      
     
 
     
-     -242 (ECPG_UNKNOWN_DESCRIPTOR_ITEM): Unknown descriptor item %s in line %d.
+     -242 (ECPG_UNKNOWN_DESCRIPTOR_ITEM)
      
       
-       The descriptor specified was not found. The statement you are trying to use has not been prepared.
+       An invalid descriptor item was requested.  (This is an internal
+       error.)  (SQLSTATE YE002)
       
      
     
 
     
-     -243 (ECPG_VAR_NOT_NUMERIC): Variable is not a numeric type in line %d.
+     -243 (ECPG_VAR_NOT_NUMERIC)
      
       
-       The database returned a numeric value and the variable was not
-       numeric.
+       During the execution of a dynamic statement, the database
+       returned a numeric value and the host variable was not numeric.
+       (SQLSTATE 07006)
       
      
     
 
     
-     -244 (ECPG_VAR_NOT_CHAR): Variable is not a character type in line %d.
+     -244 (ECPG_VAR_NOT_CHAR)
      
       
-       The database returned a non-numeric value and the variable was
-       numeric.
+       During the execution of a dynamic statement, the database
+       returned a non-numeric value and the host variable was numeric.
+       (SQLSTATE 07006)
       
      
     
 
     
-     -400 (ECPG_PGSQL): '%s' in line %d.
+     -400 (ECPG_PGSQL)
      
       
-       Some PostgreSQL error. The message
-       contains the error message from the
+       Some error caused by the PostgreSQL
+       server.  The message contains the error message from the
        PostgreSQL server.
       
      
     
 
     
-     -401 (ECPG_TRANS): Error in transaction processing line %d.
+     -401 (ECPG_TRANS)
      
       
-       The PostgreSQL server signaled that we cannot
-       start, commit, or rollback the transaction.
+       The PostgreSQL server signaled that
+       we cannot start, commit, or rollback the transaction.
+       (SQLSTATE 08007)
       
      
     
 
     
-     -402 (ECPG_CONNECT): Could not connect to database %s in line %d.
+     -402 (ECPG_CONNECT)
      
       
-       The connection attempt to the database did not work.
+       The connection attempt to the database did not succeed.
+       (SQLSTATE 08001)
       
      
     
 
     
-     100 (ECPG_NOT_FOUND): Data not found line %d.
+     100 (ECPG_NOT_FOUND)
      
       
-       This is a normal error that tells you that what
-       you are querying cannot be found or you are at the end of the
-       cursor.
+       This is a harmless condition indicating that the last command
+       retrieved or processed zero rows, or that you are at the end of
+       the cursor.  (SQLSTATE 02000)
       
      
     
    
   
+  
  
 
  
@@ -749,13 +1504,6 @@ EXEC SQL INCLUDE filename;
    in the arguments specified for output.
   
 
-  
-   ecpg is thread-safe if it is compiled using
-   the --enable-thread-safety configure
-   command-line option.  (You might need to use other threading
-   command-line options to compile your client code.)
-  
-
   
    The preprocessor program is called ecpg and is
    included in a normal PostgreSQL installation.
@@ -811,6 +1559,13 @@ ECPG = ecpg
    The complete syntax of the ecpg command is
    detailed in .
   
+
+  
+   ecpg is thread-safe if it is compiled using
+   the 
+   command-line option.  (You might need to use other threading
+   command-line options to compile your client code.)
+  
  
 
  
index 978f05ef928dd7118486d89e37699ce67c7fc988..cf4a0638717a452a65e1855508c20b914704ff40 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.18 2003/07/28 00:09:14 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.19 2003/08/01 13:53:36 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,8 +169,7 @@ PerformPortalFetch(FetchStmt *stmt,
        /* FIXME: shouldn't this be an ERROR? */
        ereport(WARNING,
                (errcode(ERRCODE_UNDEFINED_CURSOR),
-                errmsg("portal \"%s\" does not exist", stmt->portalname),
-                errfunction("PerformPortalFetch"))); /* for ecpg */
+                errmsg("portal \"%s\" does not exist", stmt->portalname)));
        if (completionTag)
            strcpy(completionTag, stmt->ismove ? "MOVE 0" : "FETCH 0");
        return;
index 5bd527d98a85b3866ab597162a76d6771dd78d50..83d9193dfd4d0c268eb6f24817fee6fa2191ac78 100644 (file)
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/interfaces/ecpg/compatlib/Makefile,v 1.5 2003/06/24 14:45:46 momjian Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/ecpg/compatlib/Makefile,v 1.6 2003/08/01 13:53:36 petere Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -16,7 +16,7 @@ NAME= ecpg_compat
 SO_MAJOR_VERSION= 1
 SO_MINOR_VERSION= 0.0
 
-override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS)
+override CPPFLAGS := -I$(top_srcdir)/src/interfaces/ecpg/include -I$(libpq_srcdir) -I$(top_srcdir)/src/include/utils $(CPPFLAGS)
 SHLIB_LINK = -L../pgtypeslib -lpgtypes -L../ecpglib -lecpg
 
 OBJS= informix.o
index 44b088481c7a8deacc1f780b9623b07cc144f1fe..1030b041ab19b4b9bcb48f66b4802f5449738cb1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.13 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.14 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -116,7 +116,7 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
        {
            if ((results = PQexec(con->connection, "begin transaction")) == NULL)
            {
-               ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL);
+               ECPGraise(lineno, ECPG_TRANS, ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN, NULL);
                return false;
            }
            PQclear(results);
@@ -130,7 +130,7 @@ ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
        {
            if ((results = PQexec(con->connection, "commit")) == NULL)
            {
-               ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL);
+               ECPGraise(lineno, ECPG_TRANS, ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN, NULL);
                return false;
            }
            PQclear(results);
@@ -154,151 +154,47 @@ ECPGsetconn(int lineno, const char *connection_name)
    return true;
 }
 
-static void
-ECPGnoticeProcessor_raise(int code, const char *message)
-{
-   struct sqlca_t *sqlca = ECPGget_sqlca();
-   sqlca->sqlcode = code;
-   strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
-   sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
-   sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
-
-   /* remove trailing newline */
-   if (sqlca->sqlerrm.sqlerrml
-       && sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] == '\n')
-   {
-       sqlca->sqlerrm.sqlerrmc[sqlca->sqlerrm.sqlerrml - 1] = 0;
-       sqlca->sqlerrm.sqlerrml--;
-   }
-
-   ECPGlog("raising sqlcode %d\n", code);
-}
-
-/*
- * I know this is a mess, but we can't redesign the backend
- */
 
 static void
-ECPGnoticeProcessor(void *arg, const char *message)
+ECPGnoticeReceiver(void *arg, const PGresult *result)
 {
+   char *sqlstate = PQresultErrorField(result, 'C');
+   char *message = PQresultErrorField(result, 'M');
    struct sqlca_t *sqlca = ECPGget_sqlca();
 
-   /* these notices raise an error */
-   if (strncmp(message, "WARNING: ", 9) && strncmp(message, "NOTICE: ", 8))
-   {
-       ECPGlog("ECPGnoticeProcessor: strange warning '%s'\n", message);
-       ECPGnoticeProcessor_raise(ECPG_WARNING_UNRECOGNIZED, message);
-       return;
-   }
-
-   message += 8;
-   while (*message == ' ')
-       message++;
-   ECPGlog("WARNING: %s", message);
-
-   /* WARNING: (transaction aborted): queries ignored until END */
-
-   /*
-    * WARNING: current transaction is aborted, queries ignored until end
-    * of transaction block
-    */
-   if (strstr(message, "queries ignored") && strstr(message, "transaction")
-       && strstr(message, "aborted"))
-   {
-       ECPGnoticeProcessor_raise(ECPG_WARNING_QUERY_IGNORED, message);
-       return;
-   }
+   int sqlcode;
 
-   /* WARNING: PerformPortalClose: portal "*" not found */
-   if ((!strncmp(message, "PerformPortalClose: portal", 26)
-        || !strncmp(message, "PerformPortalFetch: portal", 26))
-       && strstr(message + 26, "not found"))
-   {
-       ECPGnoticeProcessor_raise(ECPG_WARNING_UNKNOWN_PORTAL, message);
+   /* these are not warnings */
+   if (strncmp(sqlstate, "00", 2)==0)
        return;
-   }
 
-   /* WARNING: BEGIN: already a transaction in progress */
-   if (!strncmp(message, "BEGIN: already a transaction in progress", 40))
-   {
-       ECPGnoticeProcessor_raise(ECPG_WARNING_IN_TRANSACTION, message);
-       return;
-   }
-
-   /* WARNING: AbortTransaction and not in in-progress state */
-   /* WARNING: COMMIT: no transaction in progress */
-   /* WARNING: ROLLBACK: no transaction in progress */
-   if (!strncmp(message, "AbortTransaction and not in in-progress state", 45)
-       || !strncmp(message, "COMMIT: no transaction in progress", 34)
-       || !strncmp(message, "ROLLBACK: no transaction in progress", 36))
-   {
-       ECPGnoticeProcessor_raise(ECPG_WARNING_NO_TRANSACTION, message);
-       return;
-   }
-
-   /* WARNING: BlankPortalAssignName: portal * already exists */
-   if (!strncmp(message, "BlankPortalAssignName: portal", 29)
-       && strstr(message + 29, "already exists"))
-   {
-       ECPGnoticeProcessor_raise(ECPG_WARNING_PORTAL_EXISTS, message);
-       return;
-   }
-
-   /* these are harmless - do nothing */
-
-   /*
-    * WARNING: CREATE TABLE / PRIMARY KEY will create implicit index '*'
-    * for table '*'
-    */
-
-   /*
-    * WARNING: ALTER TABLE ... ADD CONSTRAINT will create implicit
-    * trigger(s) for FOREIGN KEY check(s)
-    */
-
-   /*
-    * WARNING: CREATE TABLE will create implicit sequence '*' for SERIAL
-    * column '*.*'
-    */
-
-   /*
-    * WARNING: CREATE TABLE will create implicit trigger(s) for FOREIGN
-    * KEY check(s)
-    */
-   if ((!strncmp(message, "CREATE TABLE", 12) || !strncmp(message, "ALTER TABLE", 11))
-       && strstr(message + 11, "will create implicit"))
-       return;
-
-   /* WARNING: QUERY PLAN: */
-   if (!strncmp(message, "QUERY PLAN:", 11))   /* do we really see these? */
-       return;
-
-   /*
-    * WARNING: DROP TABLE implicitly drops referential integrity trigger
-    * from table "*"
-    */
-   if (!strncmp(message, "DROP TABLE implicitly drops", 27))
-       return;
-
-   /*
-    * WARNING: Caution: DROP INDEX cannot be rolled back, so don't abort
-    * now
-    */
-   if (strstr(message, "cannot be rolled back"))
-       return;
+   ECPGlog("%s", message);
+
+   /* map to SQLCODE for backward compatibility */
+   if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME)==0)
+       sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
+   else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION)==0)
+       sqlcode = ECPG_WARNING_IN_TRANSACTION;
+   else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION)==0)
+       sqlcode = ECPG_WARNING_NO_TRANSACTION;
+   else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR)==0)
+       sqlcode = ECPG_WARNING_PORTAL_EXISTS;
+   else
+       sqlcode = 0;
 
-   /* these and other unmentioned should set sqlca->sqlwarn[2] */
-   /* WARNING: The ':' operator is deprecated.  Use exp(x) instead. */
-   /* WARNING: Rel *: Uninitialized page 0 - fixing */
-   /* WARNING: PortalHeapMemoryFree: * not in alloc set! */
-   /* WARNING: Too old parent tuple found - can't continue vc_repair_frag */
-   /* WARNING: identifier "*" will be truncated to "*" */
-   /* WARNING: InvalidateSharedInvalid: cache state reset */
-   /* WARNING: RegisterSharedInvalid: SI buffer overflow */
+   strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
+   sqlca->sqlcode = sqlcode;
    sqlca->sqlwarn[2] = 'W';
    sqlca->sqlwarn[0] = 'W';
+
+   strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
+   sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
+   sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
+
+   ECPGlog("raising sqlcode %d\n", sqlcode);
 }
 
+
 /* this contains some quick hacks, needs to be cleaned up, but it works */
 bool
 ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
@@ -406,7 +302,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                    if (strncmp(dbname, "unix:", 5) != 0)
                    {
                        ECPGlog("connect: socketname %s given for TCP connection in line %d\n", host, lineno);
-                       ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "", ECPG_COMPAT_PGSQL);
+                       ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : "");
                        if (host)
                            ECPGfree(host);
                        if (port)
@@ -429,7 +325,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
                {
                    ECPGlog("connect: non-localhost access via sockets in line %d\n", lineno);
-                   ECPGraise(lineno, ECPG_CONNECT, realname ? realname : "", ECPG_COMPAT_PGSQL);
+                   ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : "");
                    if (host)
                        ECPGfree(host);
                    if (port)
@@ -497,7 +393,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
                user ? "for user " : "", user ? user : "",
                lineno, errmsg);
         
-       ECPGraise(lineno, ECPG_CONNECT, db, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
        if (host)
            ECPGfree(host);
        if (port)
@@ -528,7 +424,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
    this->committed = true;
    this->autocommit = autocommit;
 
-   PQsetNoticeProcessor(this->connection, &ECPGnoticeProcessor, (void *) this);
+   PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);
 
    return true;
 }
index 361dfa73a4a6676cb8773bd05cf0f507fb7e6c3e..14e459d1b60a08f274b359ff4bcc8f290671beba 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.14 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.15 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -34,7 +34,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
    {
        if (*pval != '{')
        {
-           ECPGraise(lineno, ECPG_DATA_NOT_ARRAY, NULL, compat);
+           ECPGraise(lineno, ECPG_DATA_NOT_ARRAY, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
            return (false);
        }
 
@@ -90,13 +90,13 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                }
                else
                {
-                   ECPGraise(lineno, ECPG_MISSING_INDICATOR, NULL, compat);
+                   ECPGraise(lineno, ECPG_MISSING_INDICATOR, ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER, NULL);
                    return (false);
                }
            }
            break;
        default:
-           ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(ind_type), compat);
+           ECPGraise(lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, ECPGtype_name(ind_type));
            return (false);
            break;
    }
@@ -126,7 +126,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_INT_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -159,7 +159,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_UINT_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -192,7 +192,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_INT_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_INT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -209,7 +209,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_UINT_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -235,7 +235,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_FLOAT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -266,7 +266,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                        else if (offset == sizeof(int))
                            *((int *) (var + offset * act_tuple)) = false;
                        else
-                           ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size", compat);
+                           ECPGraise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
                        break;
                    }
                    else if (pval[0] == 't' && pval[1] == '\0')
@@ -276,7 +276,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                        else if (offset == sizeof(int))
                            *((int *) (var + offset * act_tuple)) = true;
                        else
-                           ECPGraise(lineno, ECPG_CONVERT_BOOL, "different size", compat);
+                           ECPGraise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
                        break;
                    }
                    else if (pval[0] == '\0' && PQgetisnull(results, act_tuple, act_field))
@@ -286,7 +286,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    }
                }
 
-               ECPGraise(lineno, ECPG_CONVERT_BOOL, pval, compat);
+               ECPGraise(lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                return (false);
                break;
 
@@ -396,7 +396,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_NUMERIC_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_NUMERIC_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -423,7 +423,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_INTERVAL_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_INTERVAL_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
                }
@@ -446,7 +446,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_DATE_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_DATE_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
 
@@ -468,7 +468,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    if ((isarray && *scan_length != ',' && *scan_length != '}')
                        || (!isarray && *scan_length != '\0' && *scan_length != ' '))   /* Garbage left */
                    {
-                       ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, pval, compat);
+                       ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
                        return (false);
                    }
 
@@ -477,7 +477,7 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                break;
                
            default:
-               ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(type), compat);
+               ECPGraise(lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, ECPGtype_name(type));
                return (false);
                break;
        }
index bdb308810da428913b2869d34ae21fa8c718f307..0beae2d93ab9bf336e01bc20f53e9ea2994683cc 100644 (file)
@@ -1,6 +1,6 @@
 /* dynamic SQL support routines
  *
- * $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.4 2003/08/01 08:21:04 meskes Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.5 2003/08/01 13:53:36 petere Exp $
  */
 
 #define POSTGRES_ECPG_INTERNAL
@@ -103,7 +103,7 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
            *(double *) var = (double) value;
            break;
        default:
-           ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, NULL, ECPG_COMPAT_PGSQL);
+           ECPGraise(lineno, ECPG_VAR_NOT_NUMERIC, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
            return (false);
    }
 
@@ -135,7 +135,7 @@ get_char_item(int lineno, void *var, enum ECPGttype vartype, char *value, int va
            }
            break;
        default:
-           ECPGraise(lineno, ECPG_VAR_NOT_CHAR, NULL, ECPG_COMPAT_PGSQL);
+           ECPGraise(lineno, ECPG_VAR_NOT_CHAR, ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION, NULL);
            return (false);
    }
 
@@ -162,13 +162,13 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
    ntuples = PQntuples(ECPGresult);
    if (ntuples < 1)
    {
-       ECPGraise(lineno, ECPG_NOT_FOUND, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
        return (false);
    }
 
    if (index < 1 || index > PQnfields(ECPGresult))
    {
-       ECPGraise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_INVALID_DESCRIPTOR_INDEX, ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX, NULL);
        return (false);
    }
 
@@ -300,7 +300,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
                {
                    ECPGlog("ECPGget_desc line %d: Incorrect number of matches: %d don't fit into array of %d\n",
                            lineno, ntuples, arrsize);
-                   ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL);
+                   ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
                    return false;
                }
                /* allocate storage if needed */
@@ -324,7 +324,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
 
            default:
                snprintf(type_str, sizeof(type_str), "%d", type);
-               ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, type_str, ECPG_COMPAT_PGSQL);
+               ECPGraise(lineno, ECPG_UNKNOWN_DESCRIPTOR_ITEM, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, type_str);
                return (false);
        }
 
@@ -361,7 +361,7 @@ ECPGget_desc(int lineno, char *desc_name, int index,...)
        {
            ECPGlog("ECPGget_desc line %d: Incorrect number of matches (indicator): %d don't fit into array of %d\n",
                    lineno, ntuples, data_var.ind_arrsize);
-           ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL);
+           ECPGraise(lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
            return false;
        }
        /* allocate storage if needed */
@@ -404,7 +404,7 @@ ECPGdeallocate_desc(int line, const char *name)
            return true;
        }
    }
-   ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, name, ECPG_COMPAT_PGSQL);
+   ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, name);
    return false;
 }
 
@@ -430,7 +430,7 @@ ECPGallocate_desc(int line, const char *name)
    {
        ECPGfree(new->name);
        ECPGfree(new);
-       ECPGraise(line, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(line, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
        return false;
    }
    strcpy(new->name, name);
@@ -449,7 +449,7 @@ ECPGdescriptor_lvalue(int line, const char *descriptor)
            return &i->result;
    }
 
-   ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, (char *) descriptor, ECPG_COMPAT_PGSQL);
+   ECPGraise(line, ECPG_UNKNOWN_DESCRIPTOR, ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME, (char *) descriptor);
    return NULL;
 }
 
index 0b4b563d85a3bcb3252effaa82676a3f4ee27eb4..cfeb4e65b0b4cbc849fe25b1bfabc87c22985b1d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/error.c,v 1.4 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/error.c,v 1.5 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
 #include "extern.h"
 #include "sqlca.h"
 
+
 void
-ECPGraise(int line, int code, const char *str, int compat)
+ECPGraise(int line, int code, const char * sqlstate, const char *str)
 {
    struct sqlca_t *sqlca = ECPGget_sqlca();
    sqlca->sqlcode = code;
+   strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
 
    switch (code)
    {
@@ -129,23 +131,6 @@ ECPGraise(int line, int code, const char *str, int compat)
                   "Variable is not a character type in line %d.", line);
            break;
 
-       case ECPG_PGSQL:
-           {
-               int         slen = strlen(str);
-
-               /* strip trailing newline */
-               if (slen > 0 && str[slen - 1] == '\n')
-                   slen--;
-               snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
-                        "'%.*s' in line %d.", slen, str, line);
-               if (strncmp(str, "ERROR:  Cannot insert a duplicate key", strlen("ERROR:  Cannot insert a duplicate key")) == 0)
-                   sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_DUPLICATE_KEY : ECPG_DUPLICATE_KEY;
-               else if (strncmp(str, "ERROR:  More than one tuple returned by a subselect", strlen("ERROR:  More than one tuple returned by a subselect")) == 0)
-                   sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_SUBSELECT_NOT_ONE;
-               
-               break;
-           }
-
        case ECPG_TRANS:
            snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
                     "Error in transaction processing in line %d.", line);
@@ -169,6 +154,38 @@ ECPGraise(int line, int code, const char *str, int compat)
    ECPGfree_auto_mem();
 }
 
+void
+ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat)
+{
+   struct sqlca_t *sqlca = ECPGget_sqlca();
+
+   /* copy error message */
+   snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc),
+            "'%s' in line %d.", 
+            result ? PQresultErrorField(result, 'M') : PQerrorMessage(conn),
+            line);
+   sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
+
+   /* copy SQLSTATE */
+   strncpy(sqlca->sqlstate,
+           result ? PQresultErrorField(result, 'C') : ECPG_SQLSTATE_ECPG_INTERNAL_ERROR,
+           sizeof(sqlca->sqlstate));
+
+   /* assign SQLCODE for backward compatibility */
+   if (strncmp(sqlca->sqlstate, "23505", sizeof(sqlca->sqlstate))==0)
+       sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_DUPLICATE_KEY : ECPG_DUPLICATE_KEY;
+   if (strncmp(sqlca->sqlstate, "21000", sizeof(sqlca->sqlstate))==0)
+       sqlca->sqlcode = INFORMIX_MODE(compat) ? ECPG_INFORMIX_SUBSELECT_NOT_ONE : ECPG_SUBSELECT_NOT_ONE;
+   else
+       sqlca->sqlcode = ECPG_PGSQL;
+
+   ECPGlog("raising sqlstate %.*s in line %d, '%s'.\n",
+           sqlca->sqlstate, sizeof(sqlca->sqlstate), line, sqlca->sqlerrm.sqlerrmc);
+
+   /* free all memory we have allocated for the user */
+   ECPGfree_auto_mem();
+}
+
 /* print out an error message */
 void
 sqlprint(void)
index 8e9545f0ab4b96826bd3b3f57d8108d32c3fc3cd..0d4247897d59b2049209c4306d14103e6d1474f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.21 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.22 2003/08/01 13:53:36 petere Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -124,7 +124,7 @@ create_statement(int lineno, int compat, int force_indicator, struct connection
            /* if variable is NULL, the statement hasn't been prepared */
            if (var->pointer == NULL)
            {
-               ECPGraise(lineno, ECPG_INVALID_STMT, NULL, compat);
+               ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, NULL);
                ECPGfree(var);
                return false;
            }
@@ -351,7 +351,7 @@ ECPGstore_result(const PGresult *results, int act_field,
        {
            ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d don't fit into array of %d\n",
                    stmt->lineno, ntuples, var->arrsize);
-           ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, NULL, ECPG_COMPAT_PGSQL);
+           ECPGraise(stmt->lineno, ECPG_TOO_MANY_MATCHES, ECPG_SQLSTATE_CARDINALITY_VIOLATION, NULL);
            return false;
        }
    }
@@ -362,7 +362,7 @@ ECPGstore_result(const PGresult *results, int act_field,
         */
        if (var->arrsize == 0)
        {
-           ECPGraise(stmt->lineno, ECPG_NO_ARRAY, NULL, ECPG_COMPAT_PGSQL);
+           ECPGraise(stmt->lineno, ECPG_NO_ARRAY, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
            return false;
        }
    }
@@ -481,12 +481,13 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
     * arrays are not possible unless the attribute is an array too FIXME:
     * we do not know if the attribute is an array here
     */
-
-/*  if (var->arrsize > 1 && ...)
+#if 0
+    if (var->arrsize > 1 && ...)
     {
-       ECPGraise(stmt->lineno, ECPG_ARRAY_INSERT, NULL, compat);
+       ECPGraise(stmt->lineno, ECPG_ARRAY_INSERT, ECPG_SQLSTATE_DATATYPE_MISMATCH, NULL);
        return false;
-    }*/
+    }
+#endif
 
    /*
     * Some special treatment is needed for records since we want their
@@ -757,7 +758,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
                        for (element = 0; element < var->arrsize; element++)
                            sprintf(mallocedval + strlen(mallocedval), "%c,", (((int *) var->value)[element]) ? 't' : 'f');
                    else
-                       ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size", ECPG_COMPAT_PGSQL);
+                       ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
 
                    strcpy(mallocedval + strlen(mallocedval) - 1, "]");
                }
@@ -768,7 +769,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
                    else if (var->offset == sizeof(int))
                        sprintf(mallocedval, "'%c'", (*((int *) var->value)) ? 't' : 'f');
                    else
-                       ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, "different size", ECPG_COMPAT_PGSQL);
+                       ECPGraise(stmt->lineno, ECPG_CONVERT_BOOL, ECPG_SQLSTATE_DATATYPE_MISMATCH, "different size");
                }
 
                *tobeinserted_p = mallocedval;
@@ -1021,7 +1022,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
                
            default:
                /* Not implemented yet */
-               ECPGraise(stmt->lineno, ECPG_UNSUPPORTED, (char *) ECPGtype_name(var->type), ECPG_COMPAT_PGSQL);
+               ECPGraise(stmt->lineno, ECPG_UNSUPPORTED, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (char *) ECPGtype_name(var->type));
                return false;
                break;
        }
@@ -1034,7 +1035,7 @@ ECPGexecute(struct statement * stmt)
 {
    bool        status = false;
    char       *copiedquery;
-   char       *errmsg, *cmdstat;
+   char       *cmdstat;
    PGresult   *results;
    PGnotify   *notify;
    struct variable *var;
@@ -1073,7 +1074,7 @@ ECPGexecute(struct statement * stmt)
             * We have an argument but we dont have the matched up string
             * in the string
             */
-           ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL, stmt->compat);
+           ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
            return false;
        }
        else
@@ -1111,7 +1112,7 @@ ECPGexecute(struct statement * stmt)
    /* Check if there are unmatched things left. */
    if (next_insert(copiedquery) != NULL)
    {
-       ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL, stmt->compat);
+       ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS, NULL);
        return false;
    }
 
@@ -1121,7 +1122,7 @@ ECPGexecute(struct statement * stmt)
    {
        if ((results = PQexec(stmt->connection->connection, "begin transaction")) == NULL)
        {
-           ECPGraise(stmt->lineno, ECPG_TRANS, NULL, stmt->compat);
+           ECPGraise(stmt->lineno, ECPG_TRANS, ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN, NULL);
            return false;
        }
        PQclear(results);
@@ -1134,9 +1135,8 @@ ECPGexecute(struct statement * stmt)
 
    if (results == NULL)
    {
-       errmsg = PQerrorMessage(stmt->connection->connection);
-       ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, errmsg);
-       ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat);
+       ECPGlog("ECPGexecute line %d: error: %s", stmt->lineno, PQerrorMessage(stmt->connection->connection));
+       ECPGraise_backend(stmt->lineno, NULL, stmt->connection->connection, stmt->compat);
    }
    else
 
@@ -1148,8 +1148,6 @@ ECPGexecute(struct statement * stmt)
        bool        clear_result = TRUE;
        struct sqlca_t *sqlca = ECPGget_sqlca();
 
-       errmsg = PQresultErrorMessage(results);
-       
        var = stmt->outlist;
        switch (PQresultStatus(results))
        {
@@ -1167,7 +1165,7 @@ ECPGexecute(struct statement * stmt)
                    if (ntuples)
                        ECPGlog("ECPGexecute line %d: Incorrect number of matches: %d\n",
                                stmt->lineno, ntuples);
-                   ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL, stmt->compat);
+                   ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
                    status = false;
                    break;
                }
@@ -1198,21 +1196,21 @@ ECPGexecute(struct statement * stmt)
                        }
                        else if (!INFORMIX_MODE(stmt->compat))
                        {
-                           ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, NULL, stmt->compat);
+                           ECPGraise(stmt->lineno, ECPG_TOO_FEW_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
                            return (false);
                        }
                    }
 
                if (status && var != NULL)
                {
-                   ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, NULL, stmt->compat);
+                   ECPGraise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS, ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS, NULL);
                    status = false;
                }
 
                break;
            case PGRES_EMPTY_QUERY:
                /* do nothing */
-               ECPGraise(stmt->lineno, ECPG_EMPTY, NULL, stmt->compat);
+               ECPGraise(stmt->lineno, ECPG_EMPTY, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, NULL);
                break;
            case PGRES_COMMAND_OK:
                status = true;
@@ -1225,13 +1223,13 @@ ECPGexecute(struct statement * stmt)
                            ( !strncmp(cmdstat, "UPDATE", 6)
                              || !strncmp(cmdstat, "INSERT", 6)
                              || !strncmp(cmdstat, "DELETE", 6)))
-                   ECPGraise(stmt->lineno, ECPG_NOT_FOUND, NULL, stmt->compat);
+                   ECPGraise(stmt->lineno, ECPG_NOT_FOUND, ECPG_SQLSTATE_NO_DATA, NULL);
                break;
            case PGRES_NONFATAL_ERROR:
            case PGRES_FATAL_ERROR:
            case PGRES_BAD_RESPONSE:
-               ECPGlog("ECPGexecute line %d: Error: %s", stmt->lineno, errmsg);
-               ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat);
+               ECPGlog("ECPGexecute line %d: Error: %s", stmt->lineno, PQresultErrorMessage(results));
+               ECPGraise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
                status = false;
                break;
            case PGRES_COPY_OUT:
@@ -1245,7 +1243,7 @@ ECPGexecute(struct statement * stmt)
            default:
                ECPGlog("ECPGexecute line %d: Got something else, postgres error.\n",
                        stmt->lineno);
-               ECPGraise(stmt->lineno, ECPG_PGSQL, errmsg, stmt->compat);
+               ECPGraise_backend(stmt->lineno, results, stmt->connection->connection, stmt->compat);
                status = false;
                break;
        }
@@ -1300,7 +1298,7 @@ ECPGdo(int lineno, int compat, int force_indicator, const char *connection_name,
    if (con == NULL || con->connection == NULL)
    {
        free_statement(stmt);
-       ECPGraise(lineno, ECPG_NOT_CONN, (con) ? con->name : "", stmt->compat);
+       ECPGraise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, (con) ? con->name : "");
        setlocale(LC_NUMERIC, oldlocale);
        ECPGfree(oldlocale);
        return false;
index 9f16fc24efaf49386d3cce1027967e4dd9723062..d98f158bacc0cb52473940c8ddd0b0a6a4ac78c9 100644 (file)
@@ -98,4 +98,30 @@ PGresult  **
 bool ECPGstore_result(const PGresult *results, int act_field,
                 const struct statement * stmt, struct variable * var);
 
+/* SQLSTATE values generated or processed by ecpglib (intentionally
+ * not exported -- users should refer to the codes directly) */
+
+#define ECPG_SQLSTATE_NO_DATA              "02000"
+#define ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS   "07001"
+#define ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_TARGETS      "07002"
+#define ECPG_SQLSTATE_RESTRICTED_DATA_TYPE_ATTRIBUTE_VIOLATION "07006"
+#define ECPG_SQLSTATE_INVALID_DESCRIPTOR_INDEX     "07009"
+#define ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION  "08001"
+#define ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST        "08003"
+#define ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN   "08007"
+#define ECPG_SQLSTATE_CARDINALITY_VIOLATION    "21000"
+#define ECPG_SQLSTATE_NULL_VALUE_NO_INDICATOR_PARAMETER "22002"
+#define ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION       "25001"
+#define ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION        "25P01"
+#define ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME   "26000"
+#define ECPG_SQLSTATE_INVALID_SQL_DESCRIPTOR_NAME  "33000"
+#define ECPG_SQLSTATE_INVALID_CURSOR_NAME  "34000"
+#define ECPG_SQLSTATE_SYNTAX_ERROR         "42601"
+#define ECPG_SQLSTATE_DATATYPE_MISMATCH        "42804"
+#define ECPG_SQLSTATE_DUPLICATE_CURSOR     "42P03"
+
+/* implementation-defined internal errors of ecpg */
+#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR  "YE000"
+#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY   "YE001"
+
 #endif /* _ECPG_LIB_EXTERN_H */
index 0a77da4f09528760a55bd849b54e522521f34faa..524192d7ca8891922deb04396b9c636f0ad529a9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/memory.c,v 1.3 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/memory.c,v 1.4 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -21,7 +21,7 @@ ECPGalloc(long size, int lineno)
 
    if (!new)
    {
-       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
        return NULL;
    }
 
@@ -36,7 +36,7 @@ ECPGrealloc(void *ptr, long size, int lineno)
 
    if (!new)
    {
-       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
        return NULL;
    }
 
@@ -50,7 +50,7 @@ ECPGstrdup(const char *string, int lineno)
 
    if (!new)
    {
-       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, NULL, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
        return NULL;
    }
 
index 4334844d61d6a2b66b609d6ab945a03c1cbd1edc..f42b8f721e79a70b3d96fe862bd511a34b1ab2ff 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.11 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.12 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -47,7 +47,7 @@ static struct sqlca_t sqlca_init =
        0, 0, 0, 0, 0, 0, 0, 0
    },
    {
-       0, 0, 0, 0, 0, 0, 0, 0
+       '0', '0', '0', '0', '0'
    }
 };
 
@@ -78,7 +78,7 @@ static struct sqlca_t sqlca =
        0, 0, 0, 0, 0, 0, 0, 0
    },
    {
-       0, 0, 0, 0, 0, 0, 0, 0
+       '0', '0', '0', '0', '0'
    }
 };
 #endif
@@ -103,7 +103,8 @@ ECPGinit(const struct connection * con, const char *connection_name, const int l
    ECPGinit_sqlca(sqlca);
    if (con == NULL)
    {
-       ECPGraise(lineno, ECPG_NO_CONN, connection_name ? connection_name : "NULL", ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
+                 connection_name ? connection_name : "NULL");
        return (false);
    }
 
@@ -150,7 +151,7 @@ ECPGstatus(int lineno, const char *connection_name)
    /* are we connected? */
    if (con->connection == NULL)
    {
-       ECPGraise(lineno, ECPG_NOT_CONN, con->name, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
        return false;
    }
 
@@ -179,7 +180,7 @@ ECPGtrans(int lineno, const char *connection_name, const char *transaction)
        {
            if ((res = PQexec(con->connection, transaction)) == NULL)
            {
-               ECPGraise(lineno, ECPG_TRANS, NULL, ECPG_COMPAT_PGSQL);
+               ECPGraise(lineno, ECPG_TRANS, ECPG_SQLSTATE_TRANSACTION_RESOLUTION_UNKNOWN, NULL);
                return FALSE;
            }
            PQclear(res);
index 76c58d1238cb3c9c599b8c8dff52b83e7012dc42..5569d36da07d9d28c28f747c3de6b411adc03b3e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.7 2003/08/01 08:21:04 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.8 2003/08/01 13:53:36 petere Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -120,7 +120,7 @@ ECPGdeallocate(int lineno, int c, char *name)
    }
    
    if (!ret) 
-       ECPGraise(lineno, ECPG_INVALID_STMT, name, ECPG_COMPAT_PGSQL);
+       ECPGraise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
 
    return ret;
 }
index e99c50bc8664cc15afa118ce97bb20eb9a535d2d..3f510fbfa600ec40f6351d79bc3c2b0c15a9d69e 100644 (file)
@@ -6,7 +6,8 @@
 #ifndef _ECPGLIB_H
 #define _ECPGLIB_H
 
-#include 
+#include "postgres_fe.h"
+#include "libpq-fe.h"
 
 #ifndef __BEOS__
 #ifndef __cplusplus
@@ -71,7 +72,8 @@ bool ECPGdo_descriptor(int line, const char *connection,
                  const char *descriptor, const char *query);
 bool       ECPGdeallocate_desc(int line, const char *name);
 bool       ECPGallocate_desc(int line, const char *name);
-void       ECPGraise(int line, int code, const char *str, int);
+void       ECPGraise(int line, int code, const char *sqlstate, const char *str);
+void       ECPGraise_backend(int line, PGresult *result, PGconn *conn, int compat);
 bool       ECPGget_desc_header(int, char *, int *);
 bool       ECPGget_desc(int, char *, int,...);
 
index 8af23921d78a8d66fea8f211e70be5427cfce5b9..37370b6f60589540f27ef31e5ff76dacbd6465d6 100644 (file)
@@ -50,7 +50,7 @@ struct sqlca_t
    /* 6: empty                     */
    /* 7: empty                     */
 
-   char        sqlext[8];
+   char        sqlstate[5];
 };
 
 struct sqlca_t *ECPGget_sqlca(void);
index 7e7f1fee07da05416358de8bac949ef3d2ad725d..357779863d0aa905386e9a0f9e6016e6cd0aab44 100644 (file)
@@ -1,10 +1,10 @@
-# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.38 2003/07/01 12:40:52 meskes Exp $
+# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.39 2003/08/01 13:53:36 petere Exp $
 
 subdir = src/interfaces/ecpg/test
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-override CPPFLAGS := -I$(srcdir)/../include $(CPPFLAGS)
+override CPPFLAGS := -I$(srcdir)/../include -I$(libpq_srcdir) $(CPPFLAGS)
 
 ECPG = ../preproc/ecpg -I$(srcdir)/../include