‏הצגת רשומות עם תוויות odbc. הצג את כל הרשומות
‏הצגת רשומות עם תוויות odbc. הצג את כל הרשומות

יום שלישי, יוני 11, 2024

PHP has some really odd choices in their implementation , and how I had to help a fellow that was getting "Communication link failure" when using odbc_pconnect /odbc_connect functiions in php, the only valid solution I found so far is to drop the Database part in the DSN , and then switching to the requested database

ביקשו ממני לבדוק האם אפשר להציל את המצב,, קיים קוד php ויש בעייה עם חיבור odbc לבסיס נתונים של SQL Server, החיבור היה נכשל כאשר הוא עובד תחת שרת ווב, אבל עובד בצורה תקינה אם מפעילים אותו משורת הפקודה.

כשהגעתי ראיתי שאני מקבל שגיאת Communication link failure עבור בסיס נתונים אחד, אבל לא עבור בסיס נתונים אחר תחת אותו השרת, כלומר מופע אחד של שרת  בסיס נתונים, שיש עליו מספר בסיסי נתונים שונים. בדקתי אפילו תחת משתמש sa, ואם בסיס נתונים חדש שייצרתי חם מהתנור.

בממשק המשתמש הפעלה של php -f testcase.php הכל עבד בסדר גמור, אבל הפעלה של אותו הדבר תחת apache התעופפה.

יצרתי קובץ שהוא מקרה בוחן : 



<?php
    $uid="user";
 $pwd="secretpassword";
 //Connect to a MS SQL servr over a standard ODBC connection
    $database_connection = @odbc_connect(
                    "Driver={SQL Server};Server=MY_SERVER;database=MY_DB;MARS_Connection=yes;",
                    $uid,
                    $pwd);
    //Check if our connection was valid , unfortunatly we can not use !(is_resource($database_connection) as it fails on 32 bit windows
    if (0 == $database_connection or "" == $database_connection)
    {
       error_log(__FILE__ . "(" +  __LINE___ +"): Error in odbc_connect "   . odbc_errormsg());//this will write the last odbc stack error, as we are in a testcase, there's a high chance it would be our's and not smeone else.
    }
    else
    {
        //Bring back the infromation of the local server and database name , as seen by the server, we do so , to be sure we have a valid connection and that the DB was correctly set
        $record_set = @odbc_exec($database_connection, "SELECT @@SERVERNAME,DB_NAME()");
        $result = @odbc_result_all($record_set, "border=1");
        @odbc_close($database_connection);
  }
?>
מדובר על מקרה בוחן מאוד פשוט, אני בכוונה לא משתמש ב PDO כי אני רוצה לבדוק את השכבה הנמוכה ביותר, ולא באגים שקיימים ב PDO.

למי שהולך להגיד למה אני מראה שימוש בשכבת ה ODBC (ואחרי זה במערכת OR/M אחרת) ולא ישירות ב PDO או sql_srv כי זה מאפשר עבודה יותר אגנוסטית מבחינת המערכת, אני לא נכנס לנושא האם עדיף או לא להשתמש ב PDO מאשר בקריאות ישירות , זה עניין של טעם וריח, ל PDO ישנן יתתרונות מסויימים אבל יש לו גם חסרונות, אחד החסרונות המשעמעוייתים של PDO היה בגרסאות היישנות של php  , בגריסה 5 ,הוא היה מתרסק על ימין ועל שמאל (אתם לא רוצים לדעת איך אני יודע את זה)  , לאנשים נשאר הטעם המר שלו. אבל כשאנחנו מייצרים מקרה בוחן עדיף לנו שיהיה הקוד הפשוט ביותר אם הכי פחות רכיבים להכשל.

פתרון הבניים שאני מצאתי נכון לעכשיו הוא להוציא את הגדרת בסיס הנתונים מהDSN וביצוע פעולת use $MY_DB; בשלב ההצלחה. למה זה קורה ? אני ממש לא יודע. יכול להיות עניין של הגדרות חיבור מסויומות ברמת הPHP שהוא יורש מהכין שהוא. בדקתי הגדרות אבטחה והגדרות כלליות בסיסי נתונים השונים ולא מצאתי שום דבר ייחודי שמונע את ההתחברות. אבל מכיוון שזה עובד ב php לבד אבל לא דרך apache זה משהוא הקשור בין שניהם.

למרות שזה לא הגיוני שמדובר על מקרה connection_timeout מכיוון שזה עובד עם בסיס נתונים אחד ולא אחר באותו מופע השרת, הגדלתי את הערך בהגדרות php על המחשב,לצערי הנושא לא עזר. בלוגים של SQL Server לא הצלחתי לראות את הניסונות או הכשלנות הללו , שזה די הגיוני מכייון שמדובר על שגיאה שקוראת בזמן החיבור.  כמובן שלפי הדוגמא אני לא משתמש בחיבור מוצפן (זה היה הדבר הראשון שביטלתי בשביל לבדוק) , וניסתי להשתמש גם ב DNS וגם בכתובת אינטרנט מפורשת.

בנתיים אני חופר בקוד תחת ext/odbc/ , אני מנסה לראות  איזה שהיא שגיאה שאני לזהות כתבתי די הרבה  בשפת C ו C++ בתחומי ה ODBC בעברי, אז יש לי ניסיון. הקוד .. להפעתעתי המוחלטת הקוד כתוב טוב יותר ממה שציפתי מהם האמת,ההערות שלהם ? מה אני אגיד לכם , את הtraining שלי הם לא היו עוברים כלל, אין כמעט שום הערות בקוד כמו שצריך , אין הסבר מה כל פונקציה צריכה לעשות או דוגמאות לאיך אמורים להשתמש בהם.

זה למשל:
2168 /* Persistent connections: two list-types le_pconn, le_conn and a plist
2169  * where hashed connection info is stored together with index pointer to
2170  * the actual link of type le_pconn in the list. Only persistent
2171  * connections get hashed up.
2172  */
2173 /* {{{ odbc_do_connect */
2174 void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent)
2175 {
אני מגדיר כמשהוא סביר בשביל הקוד של פהפ,

לעומת זאת זה :
 
  469 /* {{{ odbc_sql_error */
 470 void odbc_sql_error(ODBC_SQL_ERROR_PARAMS)
 471 {



אני מגדיר כהערות לא מי יודע מה טובות.

אחד הדברים שהיו הכי מוזרים בשבילי שלא מצאתי  בכלל הגדרה של TIMEOUT כאטריביוט בקוד : 

php/php8.2-8.2.18/ext/odbc$ grep TIMEOUT -rn *  
php_odbc.c:112:         if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {
php_odbc.c:165: if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {
php_odbc.c:198: if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) {


וכמובן הגדרות החיבור 
 
grep SQLSet -rn *
php_odbc.c:840:                 SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
php_odbc.c:1114:                                if (SQLSetCursorName(result->stmt, (SQLCHAR *) cursorname, SQL_NTS) != SQL_SUCCESS) {
php_odbc.c:1115:                                        odbc_sql_error(result->conn_ptr, result->stmt, "SQLSetCursorName");
php_odbc.c:1240:                        SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE, ODBCG(default_cursortype));
php_odbc.c:2069:        SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION,
php_odbc.c:2081:                rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt);
php_odbc.c:2083:                        odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption");
php_odbc.c:2575:                rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, pv_onoff ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
php_odbc.c:2674:                case 1:         /* SQLSetConnectOption */
php_odbc.c:2683:                        rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val);
php_odbc.c:2689:                case 2:         /* SQLSetStmtOption */
php_odbc.c:2694:                        rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val);
php_odbc.c:2702:                        zend_argument_value_error(2, "must be 1 for SQLSetConnectOption(), or 2 for SQLSetStmtOption()");

 
מה שאני ציפיתי לראות היו קריאות  SqlSetStmtAttr עם מזהה SQL_QUERY_TIMEOUT  (מדבר על כמה זמן בקשה תיקח) או לפחות שימוש ב SQLSetConnectAttr ולא שימוש ב SQLSetStmtOption  שהיא רק עבור ODBC 1.0, כן PHP 8.0 נותנים תמיכה לאחור ב API לשנת 1992 , אני לא צוחק!

הייתי מצפה לראות לפחות משהוא כמו
SQLSetConnectAttr(V_OD_hdbc, SQL_LOGIN_TIMEOUT /*103*/, (SQLPOINTER *) timeout_value, 0); //we could use 113 for connection timeout too instead of 103 (SQL_LOGIN_TIMEOUT)
(זה כמובן במידה והם היו בוחרים לעבוד בצורה הזאת, ושה timeout_value ייקרא מתוך php.ini)

עכשיו אני יודע שיגיע מישהוא ויגיד לי , אתה לא הסתקלת על odbc_setoption , אמסור לו  , הרשו לי לומר, זו אחת ממקרי התיעוד הגרועים ביותר שראיתי, והשימוש בו , ... עוד יותר גרוע. יש לנו מושג שנקרה constants לא סתם,והכי חשוב אין אפילו קריאה אחת בלבד בכל הקוד! אז כן , אני יכול להפעיל אותו אחרי חיבור, אבל בהצלחה להבין איך אני עושה את זה *לפני* שהחיבור התבצע, זה למה הלכתי לקוד לראות מה ישפיע על הגדרות ה attribute בקוד המקוד של PHP, לצערי לא הצלחתי למצוא את הקוד שמפעיל את הגדרות ברירת המחדל כלל. חיפשתי אפילו את הערכים המספריים של הקבועים שמדברים על timeout בקוד המקור ולא הצלחתי לאתר אותם.


אני נגעתי בקוד ה php הזה כתמכנת בשפת C ולא כמתכנת ב php, זה לא הופך אותי למי שמבין בזה או אוהב את זה.

קישור לפרטי הרכיבים בDSN.
קישור למידע אפשרויות החיבור  בשרתי SQL Server לדריברים של php.

יום שישי, אפריל 22, 2016

עבודה עם PG דרך ODBC

כשעובדים עם בסיס נתונים אפשר לעבוד קשה ולהשתמש בפקודות הספציפיות לבסיס הנתונים (כמו למשל PGConnect). ואפשר לעבוד בשיטה הסטראדנרטית שימוש ב ODBC.

בשביל לגשת ולהשתמש ב PG תחת ODBC קודם כל נגדיר DSN עבורו בדביאן קודם נתקין את הדריבר (מתוך  odbc-postgresql)

 זה יראה כך במקרה של UNICODE:

[otherdb]
Description         = PostgreSQL connection to otherdb
Driver              = PostgreSQL Unicode
Database            = otherdb
Servername          = 192.168.1.35
UserName            = 
Password            = 
ReadOnly            = No
RowVersioning       = No
ShowSystemTables    = No
Trace               = No 
#uncomment for traces
#TraceFile           = /tmp/psqlodbc.log 

לאחר מכן בקוד שלנו נוכל להתחבר באמצעות התחביר הבא :

"DSN=otherdb;DATABASE=otherdb;UID=%s;PWD=%s"  
את ה %s כמובן מחליפים לפי הנתונים הנכונים.

חשוב לזכור שאת המידע עצמו אנו צריכים לקודד ל unicode בעצמינו, בחלק מהספריות זה כבר יתבצע עבורנו (למשל תחת java) אבל במקרים אחרים נדרש לקידוד עצמאי.

יום שישי, ינואר 06, 2012

איך לשלוף נתונים מקבצי mdb בדביאן

ב 2003-5 עזרתי לפתח מערכת של ניהול מלאי. מכיוון שלא היה לי אפשרות להשתמש ב קומפיילר ומה שהיה ברשותי היה רק כלי office אספנו ופיתחנו מערכת שידעה בהתאם לתיאור של הכלי לתת את הקישור למסח"א , מק"ט מספר יצרן או שם פריט.
לפני שהעברנו את הקוד פנימה יצרנו מערכת דמה שעבדה על Win XP. לא מזמן פגשתי את השותף לפיתוח וחשבתי לראות בעיניים עם ניסיון על פתרון שנכתב אי שם לפני שנים.

1. האם אני יכול לגשת למידע.
2. האם אני להשתמש בטפסים ובקוד שקיים (VBS ).

המידע מאוחסן ב mdb שנוצר ע"י אקסס ואני משתמש במערכת דביאן / גנו לינוקס, אז אמרתי איך אני שולף את המידע ?

שברתי את הראש איך לשלוף את המידע ואז גילתי את mdbtools :
apt-cache search mdbtools
libreoffice-base - office productivity suite -- database
libmdbtools - mdbtools libraries
mdbtools - JET / MS Access database (MDB) tools
mdbtools-dev - mdbtools development files
mdbtools-gmdb - JET / MS Access database (MDB) file viewer
באמצעות הכלי הנראה mdbtools ניתן לגשת למידע שמאוחסן בקבצי MDB (יש לי קבצים שנוצרו ב access 2000 ) :

Gui :

mdbtools-gmdb - כמה שזה עצוב הממשק מזכיר מאוד את Access 97 (אני מרגיש דינוזאור), אבל לאנשים שזוכרים את אקסס ושומרים לו חסד נעורים יבינו איך לעבוד.
הוא הצליח  המידע הגולמי היה זמין עבור northwind :
 CLI:

mdbtool-tables - מציג את הטבלאות.
mdb-tables Nwind.mdb

Order Details Orders Products Shippers Categories Customers Employees Suppliers

mdbtool-schema - מציג את הסכמה.



mdb-schema Nwind.mdb

-------------------------------------------------------------                                                                                                                      
-- MDB Tools - A library for reading MS Access database files                                                                                                                      
-- Copyright (C) 2000-2004 Brian Bruns                                                                                                                                             
-- Files in libmdb are licensed under LGPL and the utilities under                                                                                                                 
-- the GPL, see COPYING.LIB and COPYING files respectively.                                                                                                                        
-- Check out http://mdbtools.sourceforge.net                                                                                                                                       
-------------------------------------------------------------                                                                                                                      
                                                                                                                                                                                   
DROP TABLE Order Details;                                                                                                                                                          
CREATE TABLE Order Details                                                                                                                                                         
 (                                                                                                                                                                                 
        OrderID                 Long Integer,                                                                                                                                      
        ProductID                       Long Integer,                                                                                                                              
        UnitPrice                       Currency,                                                                                                                                  
        Quantity                        Integer,                                                                                                                                   
        Discount                        Single                                                                                                                                     
);                                                                                                                                                                                 
-- CREATE ANY INDEXES ...                                                                                                                                                          
                                                                                                                                                                                   
DROP TABLE Orders;                                                                                                                                                                 
CREATE TABLE Orders                                                                                                                                                                
 (                                                                                                                                                                                 
        OrderID                 Long Integer,                                                                                                                                      
        CustomerID                      Text (5),                                                                                                                                  
        EmployeeID                      Long Integer,                                                                                                                              
        OrderDate                       DateTime (Short),                                                                                                                          
        RequiredDate                    DateTime (Short),                                                                                                                          
        ShippedDate                     DateTime (Short),
        ShipVia                 Long Integer,
        Freight                 Currency,
        ShipName                        Text (40),
        ShipAddress                     Text (60),
        ShipCity                        Text (15),
        ShipRegion                      Text (15),
        ShipPostalCode                  Text (10),
        ShipCountry                     Text (15)
);
-- CREATE ANY INDEXES ...

DROP TABLE Products;
CREATE TABLE Products
 (
        ProductID                       Long Integer,
        ProductName                     Text (40),
        SupplierID                      Long Integer,
        CategoryID                      Long Integer,
        QuantityPerUnit                 Text (20),
        UnitPrice                       Currency,
        UnitsInStock                    Integer,
        UnitsOnOrder                    Integer,
        ReorderLevel                    Integer,
        Discontinued                    Boolean
);
-- CREATE ANY INDEXES ...

DROP TABLE Shippers;
CREATE TABLE Shippers
 (
        ShipperID                       Long Integer,
        CompanyName                     Text (40),
        Phone                   Text (24)
);
-- CREATE ANY INDEXES ...

DROP TABLE Categories;
CREATE TABLE Categories
 (
        CategoryID                      Long Integer,
        CategoryName                    Text (15),
        Description                     Memo/Hyperlink (255),
        Picture                 OLE (255)
);
-- CREATE ANY INDEXES ...

DROP TABLE Customers;
CREATE TABLE Customers
 (
        CustomerID                      Text (5),
        CompanyName                     Text (40),
        ContactName                     Text (30),
        ContactTitle                    Text (30),
        Address                 Text (60),
        City                    Text (15),
        Region                  Text (15),
        PostalCode                      Text (10),
        Country                 Text (15),
        Phone                   Text (24),
        Fax                     Text (24)
);
-- CREATE ANY INDEXES ...

DROP TABLE Employees;
CREATE TABLE Employees
 (
        EmployeeID                      Long Integer,
        LastName                        Text (20),
        FirstName                       Text (10),
        Title                   Text (30),
        TitleOfCourtesy                 Text (25),
        BirthDate                       DateTime (Short),
        HireDate                        DateTime (Short),
        Address                 Text (60),
        City                    Text (15),
        Region                  Text (15),
        PostalCode                      Text (10),
        Country                 Text (15),
        HomePhone                       Text (24),
        Extension                       Text (4),
        Photo                   OLE (255),
        Notes                   Memo/Hyperlink (255),
        ReportsTo                       Long Integer
);
-- CREATE ANY INDEXES ...

DROP TABLE Suppliers;
CREATE TABLE Suppliers
 (
        SupplierID                      Long Integer,
        CompanyName                     Text (40),
        ContactName                     Text (30),
        ContactTitle                    Text (30),
        Address                 Text (60),
        City                    Text (15),
        Region                  Text (15),
        PostalCode                      Text (10),
        Country                 Text (15),
        Phone                   Text (24),
        Fax                     Text (24),
        HomePage                        Memo/Hyperlink (255)
);
-- CREATE ANY INDEXES ...



-- CREATE ANY Relationships ...

-- relationships are not supported for access


ממשק תכנות באמצעות mdbtools-dev בשפת C

טוב לאחר שיש לי גישה למידע האם אפשר להריץ את הקוד ולעבוד ?
כנראה שאני מפספס משהוא אבל אני ממש לא מצליח להפעיל את ה formים שנכתבו ונערכו , בעסה אבל לא נורא.

אולי זה הזדמנות מצויינת לכתוב ממשק ב QT לעבודה מול זה.

יום שני, נובמבר 28, 2011

Inserting LONGVARBINARY into MS SQL Server

נתקעתי בבעיה קטנה של המרת קוד ישן שעובד עם freetds + unixodbc בשביל להכניס מידע לבסיס נתונים של MS SQL.
כזכור הסוג IMAGE יורד בהקדם אז צריך לעשות המרה של הקוד שמטפל בזה לאחרים.
אז הנה דוגמה לשימוש ב כfreetds ע"ג odbc בשביל לשלוח מידע שיכול לאחסן קבצים.


/*

    Copyright 2011  Boris Shtrasman boris sh 1983 at gmail dot com

    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appear in all
    copies and that both that the copyright notice and this
    permission notice and warranty disclaimer appear in supporting
    documentation, and that the name of the author not be used in
    advertising or publicity pertaining to distribution of the
    software without specific, written prior permission.

    The author disclaim all warranties with regard to this
    software, including all implied warranties of merchantability
    and fitness.  In no event shall the author be liable for any
    special, indirect or consequential damages or any damages
    whatsoever resulting from loss of use, data or profits, whether
    in an action of contract, negligence or other tortious action,
    arising out of or in connection with the use or performance of
    this software.

*/
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>

#define TABLE_NAME "binary_v3"

static void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type);



int main()
{
   #undef UNICODE /* for the Win ppl */
   SQLHENV henv;
   SQLHDBC dbc;
   SQLHSTMT stmt;

   RETCODE retcode;

   SQLLEN cbTextSize, lbytes;
   PTR pParmID;
   char binary_data[8024]="";

   memset(binary_data,0,sizeof(binary_data));
   binary_data[1] = 5;

   //lets define some strage number for batch  
   SDWORD batch_size = sizeof(binary_data) - 1024;

   // Allocate the ODBC environment and save handle.
   retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) 
   {
      printf("SQLAllocHandle(Env) Failed\n\n");
      goto cleanup;
   }

   // Notify ODBC that this is an ODBC 3.0 app.
   retcode = SQLSetEnvAttr(henv, 
        SQL_ATTR_ODBC_VERSION,
           (SQLPOINTER) SQL_OV_ODBC3,
                SQL_IS_INTEGER);

   if ( 
       (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) 
   {
      printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
      goto cleanup;
   }

   // Allocate ODBC connection handle and connect.
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &dbc);
   if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS))
   {
      printf("SQLAllocHandle(dbc) Failed\n\n");
      goto cleanup;
   }
     
   SQLCHAR odbc_dsn_string_dump[255];
   SQLSMALLINT odbc_dsn_string_dumpLen;

   retcode = SQLDriverConnect(
           dbc,
           NULL,
           (SQLCHAR *)"Driver=FreeTds;"
                "SERVER=192.168.1.2\\SQLEXPRESS;UID=sa;"
                "PWD=pwd;DATABASE=db",
           SQL_NTS,
           odbc_dsn_string_dump,
           sizeof(odbc_dsn_string_dump),
           &odbc_dsn_string_dumpLen,
           SQL_DRIVER_COMPLETE);
   
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) 
   {
      extract_error("Describe param",dbc, SQL_HANDLE_DBC);  
       
      goto cleanup;
   }

   // Allocate statement handle.
   retcode = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) 
   {
      extract_error("Allocation ... ",stmt, SQL_HANDLE_STMT);  
       
      goto cleanup;
   }

   //tell the driver to work only in sync mode !
   SQLSetStmtOption(dbc, SQL_ASYNC_ENABLE, SQL_ASYNC_ENABLE_OFF);

   if (SQL_SUCCESS !=  SQLExecDirect(stmt,  (SQLCHAR *)
            "IF EXISTS "
            "(SELECT * FROM sysobjects WHERE id = "
            "object_id(N'[dbo].[" TABLE_NAME "]') "
            "AND OBJECTPROPERTY(id, N'IsUserTable') = 1) "
            "DROP TABLE [dbo].[" TABLE_NAME "]; " 
            "CREATE TABLE [dbo].[" TABLE_NAME "] "
            "( name varchar(256), content varbinary(max) NOT NULL ); ",    
            SQL_NTS))
   {
      extract_error("drop + create table ... ",stmt, SQL_HANDLE_STMT);  
       
      goto cleanup;
 
   }
   
   lbytes = (SDWORD) sizeof(binary_data);
   //we are setting the length to be calculated on run time.
   cbTextSize = SQL_LEN_DATA_AT_EXEC(lbytes);

   // Bind the parameter marker.
   
   SQLSMALLINT    binded_column_type,
                  persicion_in_binded_column,
                  is_binded_type_nullable;
   
   SQLUINTEGER   binded_column_size_from_driver = 0;
   
   retcode = SQLPrepare( stmt,
                         (SQLCHAR*)"INSERT INTO " 
                                    TABLE_NAME 
                        " (name, content) VALUES ('file', ?)",SQL_NTS);

#if 0

//for now freetds does not support describe param 
// but on the second it does I must use describe
//      param inorder to get the correct sizes and column types
   retcode = SQLDescribeParam(stmt,
         1,
         &binded_column_type,
         &binded_column_size_from_driver,
         &persicion_in_binded_column,
         &is_binded_type_nullable);

   printf ("Desc info (%d) %d %d %d %d\n",retcode , binded_column_type , 
binded_column_size_from_driver, persicion_in_binded_column, is_binded_type_nullable);

   if (binded_column_type != SQL_LONGVARBINARY) 
   {
        printf("This is strange got %d instead of %d\n" , 
binded_column_type, SQL_LONGVARBINARY);
   }

   if (SQL_SUCCESS != retcode ) 
   {
     extract_error("Describe param",stmt, SQL_HANDLE_STMT);  
         goto cleanup;
   }
#else
    binded_column_size_from_driver = 0;//Don't ask me why freetds\
 fails to work with the 2G size 
#endif

   retcode = SQLBindParameter(stmt, 
                              1, 
                              SQL_PARAM_INPUT,
                              SQL_C_BINARY,
                              SQL_LONGVARBINARY,
                              binded_column_size_from_driver
                                        /*2147483647 vs 32K*/,
                              0,
                              (VOID *) 1/* any value other then null*/,
                              0,
                              &cbTextSize);
    
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
      extract_error("Bind param param",stmt, SQL_HANDLE_STMT);  
      goto cleanup;
   }

   // Execute the command.
   retcode = SQLExecDirectA(
                stmt, 
                (SQLCHAR *)"INSERT INTO " 
                            TABLE_NAME 
                           " (name, content) VALUES ('file', ?)", SQL_NTS);
   
   if ( 
        (retcode != SQL_SUCCESS) 
           &&
        (retcode != SQL_NEED_DATA)
           && 
        (retcode != SQL_SUCCESS_WITH_INFO) )
   {
      extract_error("Insert",stmt, SQL_HANDLE_STMT);  
      goto cleanup;
   }

   // We set up the data len to be computed on executing therefor we must \
         actually send the data.
   // prior to calling put data you must first call to SQLParamData .. \
         why, only the odbc masters know 
   retcode = SQLParamData(stmt, &pParmID);
   printf("SQLParam Data = %d \n",retcode);

   if (SQL_NEED_DATA != retcode)
   {
      extract_error("grrr ... ",stmt , SQL_HANDLE_STMT);
      goto cleanup;
   }

   char * pt_data_be_inserted_into_db = binary_data;
   //we defined that data len will be calculated on executing \
        this is the reason why we got this value
  
   if (retcode == SQL_NEED_DATA) 
   {
      
      while (lbytes > batch_size)
      {

         retcode = SQLPutData(stmt,
                   (SQLCHAR*) pt_data_be_inserted_into_db, batch_size);
         lbytes -= batch_size;
         pt_data_be_inserted_into_db += batch_size;
      }
      // Put final batch.
      retcode = SQLPutData(stmt, pt_data_be_inserted_into_db, lbytes); 
      printf("last put data with %d bytes and exited with %d\n", lbytes,retcode);
   
      if ( 
           (retcode != SQL_SUCCESS)
              && 
           (retcode != SQL_SUCCESS_WITH_INFO) )
      {
         extract_error("Put data for stmt",stmt, SQL_HANDLE_STMT);  
         goto cleanup;
      }
     
   }
  
   // send the data to the db.
   retcode = SQLParamData(stmt, &pParmID);
   if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) 
   {
      extract_error("Final Param data",stmt, SQL_HANDLE_STMT);  
      goto cleanup;
   }
   
cleanup:
   // Clean up.
   SQLFreeHandle(SQL_HANDLE_STMT, stmt);
   SQLDisconnect(dbc);
   SQLFreeHandle(SQL_HANDLE_DBC, dbc);
   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   return 0;
}

void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type)
{
    SQLINTEGER     i = 0;
    SQLINTEGER     native;
    SQLCHAR     state[ 7 ];
    SQLCHAR     text[256];
    SQLSMALLINT     len;
    SQLRETURN     ret;

    fprintf(stderr,
            "\n"
            "The driver reported the following diagnostics whilst running "
            "%s\n\n",
            fn);

    perror("Last os error :");
    do
    {
        ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
                            sizeof(text), &len );
        if (SQL_SUCCEEDED(ret))
            printf("%s:%ld:%ld:%s\n", state, i, native, text);
    }
    while( ret != SQL_NO_DATA );
    fprintf(stderr, "found %d elements of information\n",(i>0)?i - 1:0);
}

יום שני, נובמבר 21, 2011

Denali is a great feture ...

 טוב קיבלתי לידי התקנת SQL Denali , מה אני יכול לספר אם זה ייציב בשביל מפתחים אז מישהוא אימץ את  שיטת שהמשתמשים יעשו QA.

רק לספר לכם על התהליך שהמכונה הזאת עברה (משידרוג של sql server 2008 R2) - כמה שגיאות מדהימות בשביל התענוג :
הכל התחיל מexceptions מבסיס נתונים

אז אמרתי טוב בשביל מה יש בסיס התקנה לידך :



בשביל לתקן את זה צריך לייצר חשבון משתמש שונה מnetbios name (שם מחשב), טוב אמרתי יאללה אולי שווה לי לעבוד עם denali ?






אהה מה עושים במצב כזה תשאלו ?
מקללים ומסירים כל דבר שקשור ל SQL Server (כולל compat) - לפני זה תכינו את הדיסק של VS2010 כי ההתקנה שלכם הולכת פיפאן.
מקללים עוד קצת כי אז מקבלים :


זה בסדר תרגישו טוב אתם רק בודקי תוכנה בחינם :-)

יופי הצלחת לעדכן את בסיס הנתונים ואתם מקבלים שגיעה שאי אפשר לפתוח VS 2010 כי חלק מהאלמנטים השתדרגו , לפי פורמים כל מה שצריך לעשות זה לבצע תיקון של ההתקנה :
זה בסדר , זו רק שגיאה שמצריכה להפעיל מחדש את המחשב ולנסות לעשות תיקון נוסף ...


משהוא חשוב בשביל לספר לכם תחזיקו שני instances של סביבת העבודה שלכם אחת ל SQL ואחת ל C הסיבה היא פשוטה: ביום אחד קרוב ל12 נפילות של הclient , אם חשבתם ש VS 2010 הוא איטי (על מחשב עם 4 ג"ב זכרון וכונן 7200) אז תתכונו לסיוט.
משהוא קטן אני עובד עם win7 מעודכן ללא שום תוכנות חיצוניות פרט לנדרשות (אני מהאנשים שאסרו עליהם להתקין vim).

זהוא סיימנו עם סיפורי הגבורה עם שירותי ה SQL :-) ונעבור לקצת קוד פתוח..

לאחר הערה של ארתיום על אי התמיכה ביוניקוד ב freetds החלטתי לבדוק מה עוד יהיה חסר (עדיף לדעת על צרות לפני זה).

לפתע אני לא מצליח להתחבר מ freetds עם שגיעה קריפטית:



UNICODE Using encoding ASCII 'ISO8859-1' and UNICODE 'UCS-2LE' 
DIAG [08S01] [FreeTDS][SQL Server]Unable to connect: Adaptive Server is unavailable or does not exist   

DIAG [S1000] [FreeTDS][SQL Server]Unable to connect to data source 
אם אתם יודעים על מה מדובר על הכבוד לכם , זו דוגמה מצויינת להודעת שגיעה (כי היא משגעת ).
מדובר למעשה על בעיית חיבור שלא מתורגמת כמו שצריך.

טוב קופצים למכונה רואים שהפורט נכון שהכל כביכול עובד אבל אין חיבור.
חיפוש נוסף מגלה שלמרות שהגדרתי פורט להאזנה בשדה ipall פיספסתי שאני חייב לעבור שדה שדה ולמחוק תוכן מ dynamic ports, בסיום ההגדרה אצלי זה נראה כך :


בסדר נגמר יש אפילו חיבור :

#include <stdio.h>
#include <sql.h>
#include <sqlext.h>


static void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type);

main() {
  SQLHENV env;
  SQLHDBC dbc;
  SQLHSTMT stmt;
  SQLRETURN ret; /* ODBC API return status */
  SQLCHAR outstr[1024];
  SQLSMALLINT outstrlen;

  /* Allocate an environment handle */
  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
  /* We want ODBC 3 support */
  SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
  /* Allocate a connection handle */
  SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
  /* Connect to the DSN mydsn */
  ret = SQLDriverConnect(dbc, NULL, "Driver=FreeTds;SERVER=192.168.1.2\\SQLEXPRESS;UID=username;PWD=pwd;DATABASE=master", SQL_NTS,
                         outstr, sizeof(outstr), &outstrlen,
                         SQL_DRIVER_COMPLETE);
  if (SQL_SUCCEEDED(ret)) {
    printf("Connected\n");
    printf("Returned connection string was:\n\t%s\n", outstr);
    if (ret == SQL_SUCCESS_WITH_INFO) {
      printf("Driver reported the following diagnostics\n");
      extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
    }
    SQLDisconnect(dbc);         /* disconnect from driver */
  } else {
    fprintf(stderr, "Failed to connect\n");
    extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
  }
  /* free up allocated handles */
  SQLFreeHandle(SQL_HANDLE_DBC, dbc);
  SQLFreeHandle(SQL_HANDLE_ENV, env);
}

void extract_error(
    char *fn,
    SQLHANDLE handle,
    SQLSMALLINT type)
{
    SQLINTEGER   i = 0;
    SQLINTEGER   native;
    SQLCHAR      state[ 7 ];
    SQLCHAR      text[256];
    SQLSMALLINT  len;
    SQLRETURN    ret;

    fprintf(stderr,
            "\n"
            "The driver reported the following diagnostics whilst running "
            "%s\n\n",
            fn);

    do
    {
        ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
                            sizeof(text), &len );
        if (SQL_SUCCEEDED(ret))
            printf("%s:%ld:%ld:%s\n", state, i, native, text);
    }
    while( ret == SQL_SUCCESS );
}