Package: python4DBI
Python4DBIIn Memory Of Edson de Sousa (14/04/94 - 16/08/18), i will see you againTable of contentsGeneral infoTechnologiesSetupAPICursorPropertiesrow_numberrow_countdescriptionMethodscloseprepare_statementset_input_sizesset_output_sizeexecutefetch_onefetch_manyfetch_allstart_transactioncancel_transactionrollbackcommitvalidate_transactionsend_messages_in_base_64set_protocol_versionset_preferred_image_typesset_fmtprint_resultDatabase InterfaceMethodsconnectclosecursorconnectedget_socketget_socket_timeoutget_hostget_portget_userget_passwordget_loggerExamplesGeneral info4D is an incredibly productive development platform that lets you focus on your data model and your business rules.The 4D framework takes care of running your application code natively on macOS and Windows.The 4DBI is written in pure python and allows a python program to use SQL to access one or more databases from a
single application without using the 4D ODBC driver.4D and 4D Server both provide a native SQL server that enables this functionality.TechnologiesProject is created with:Pythontexttable -https://github.com/foutaise/texttable/SetupTo run this project, install it locally using pip:$ pip install python4DBIAPICursorIt consists of pure application logic, which interacts with the database.
It includes all the information to represent data to the end user.Propertiesrow_numberReturn: int or NoneThis read-only attribute provides the current 0-based index of the cursor in the result set
or None if the index cannot be determinedrow_countReturn: intThis read-only attribute specifies the number of rows that the last .execute*()descriptionReturn: ListA Cursor object's description attribute returns information about each of the result columns of a query.MethodscloseReturn: NoneClose the current 4D SQL server cursorprepare_statementParams: query ( str )
	Return: intChecks if the statement is valid should always be execute before an execute statement
returns FOURD_OK or FOURD_ERRORset_input_sizesNot implemented!Params: size ( int )
	Return: NoneThis can be used before a call to .execute*() to predefine memory areas for the operation's parameters.set_output_sizeNot implemented!Params: size ( int )
	Return: NoneSet a column buffer size for fetches of large columns (e.g. LONGs, BLOBs, etc.).
the column is specified as an index into the result sequence.
Not specifying the column will set the default size for all large columns in the cursor.executeParams: query (str), params (dict), page_size (int), on_before_execute (funtion), on_executed (funtion), *args, **kwargs
	Return: NonePrepare and execute a database operation (query or command).fetch_oneReturn: List or NoneFetch the next row of a query result set, returning a single sequence, or None when no more data is available.fetch_manyParams: size (int)
	Return: Two-dimensional List or NoneFetch the next set of rows of a query result, returning a sequence of sequences (e.g. a list of tuples).
An empty sequence is returned when no more rows are available.fetch_allReturn: Two-dimensional List or NoneFetch all (remaining) rows of a query result.
Note that the cursor's array size attribute can affect the performance of this operation.start_transactionReturn: NoneOpens a transactioncancel_transactionReturn: NoneRollback an open transaction
Same operation as rollback methodrollbackReturn: NoneRollback an open transaction
Same operation as cancel_transaction methodcommitReturn: NoneCommits an open transaction
Same operation as validate_transaction methodvalidate_transactionReturn: NoneCommits an open transaction
Same operation as commit methodsend_messages_in_base_64Params: use_b64 (bool)
	Return: NoneSets the base 64 modeset_protocol_versionParams: protocol_version (str)
	Return: NoneSets the 4D SQL server protocol versionset_preferred_image_typesParams: preferred_image_types (str)
	Return: NoneSets the preferred image typeCurrently only supports 'png' pr 'jpg' formatsset_fmtParams: fmt (str)
	Return: NonePrints a 4D SQL server cursor resultSets the type of binary architectureCurrently supports the following formats:'<' little-endian for MAC OS X - RVLB'>'	big-endian for Windows - BLVRprint_resultParams: headers (List), rows (List), max_width (int), logger(obj)
	Return: NoneDatabase InterfaceIt acts as an intermediary between view and modelMethodsconnectParams:	** kwargs
	Return: NoneOpens a socket connection to the 4D SQL Serverkwargs supported are:socket_timeout : int (default 10)dsn : str (default '')host : str (default '127.0.0.1')port : int (default 19812)user : str (default '')password : str (default '')closeReturn: NoneCloses the current 4D SQL server socket connectioncursorReturn: _python4DCursor objectReturns a 4D SQL server cursor objectconnectedReturn: boolReturns true if the socket is connected to the 4D SQL server and false otherwiseget_socketReturn: self._socket objectReturns the current socket objectget_socket_timeoutReturn: intReturns the current socket timeoutget_hostReturn: strReturns the current to 4D SQL server hostget_portReturn: intReturns the current to 4D SQL server portget_userReturn: strReturns the current to 4D SQL server userget_passwordReturn: strReturns the current to 4D SQL server passwordget_loggerReturn: strReturns the logger objectExampleimporttimefrompython4DBI.python4DBIimportpython4DBIcon=python4DBI()con.connect(user='theUser',password='thePassword')cursor=con.cursor()t0=time.time()cursor.execute(query='SELECT * FROM EMPLOYEES')ifcursor.row_count>0:result=cursor.fetch_all()con.print_result(headers=cursor.description,rows=result)t1=time.time()total=t1-t0+------------+--------+----------+----------+----------+----------+----------+----------+-----------+------+---------+-----------+--------+-------+-------+------+
| EmployeeID | Last   | Name     | First    | Name     | Address1 | Address2 | Zip      | Code      | City | Country | Telephone | Mobile | Phone | Birth | Date |
+------------+--------+----------+----------+----------+----------+----------+----------+-----------+------+---------+-----------+--------+-------+-------+------+
| 1          | Barros | Marciano | Address1 | Address2 | 9000     | FUNCHAL  | Portugal | 3.510e+09 |      | None    |           | None   | None  |       |      |
+------------+--------+----------+----------+----------+----------+----------+----------+-----------+------+---------+-----------+--------+-------+-------+------+

Execution time : 0.022388219833374023Template example 1"""Learn how to open a connection to the 4D SQL Server."""# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')# Check if the socket is connectedifcon.connected()isTrue:# Do stuffpass# Close the socket connectioncon.close()Template example 2"""Learn to open a connection to the 4D SQL Server and handle the exceptions.To learn more about the exceptions raised at a particular method please read the doc strings.For example:- help(python4DBI) will print the documentation for the 4DBI interface- help(python4DBI.__init) will print the documentation for the 4DBI constructor."""try:# Instantiate a connection objectcon=python4DBI()exceptOperationalError:# Handle errorcon=NoneexceptExceptionase:# Handle errorcon=Noneifcon:try:# Authenticationcon.connect(user='theUser',password='thePassword')exceptProgrammingError:# Handle errorpassexceptOperationalError:# Handle errorpassexceptExceptionase:# Handle errorpassifcon.connected():# Do stuffpasstry:# Close the socket connectioncon.close()exceptExceptionase:# Handle errorpassTemplate example 3"""As we have seen in previous examples handling errors will exponentiate the number of try/except casesbecause every function on the DBI will have the potential of raising errors in this example I will showhow to simplify the 'try catch' with the usage of superclass's.4DBI Error Classes ListStandardError|__Warning|__Error|__InterfaceError|__DatabaseError|__DataError|__OperationalError|__IntegrityError|__InternalError|__ProgrammingError|__NotSupportedError"""try:# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Do stuffpass# Close the socket connectioncon.close()exceptWarningase:# Handle warningpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 4"""I will show how to change the standard logging file and level.Note: All exception raised are logged before being raised.The default logging file is "python4DBI.log" and the default level is CRITICAL.The 'logging_file' should be the absolute file path by default is the same path as the module.Be careful enabling DEBUG level logging, will make the DBI slower, because every iteration withthe DB will be logged and such configuration is not recommended for production environments."""try:# Instantiate a connection object with custom logging level and log locationcon=python4DBI(logging_level=logging.DEBUG,logging_file='../python4DBI.log')# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Do stuffpass# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 5"""Getting a 4D cursor.The 4D cursor database cursor is a control structure that enables traversal over the records in a database.Cursors facilitate subsequent processing in conjunction with the traversal, such as retrieval, additionand removal of database records.Cursors are used by database programmers to process individual rows returned by database system queries.Cursors enable manipulation of whole result sets at once.Note: Normally a cursor can be viewed as a pointer to one row in a set of rows.The cursor can only reference one row at a time, but can move to other rows of the result set as needed.In this DBI was not possible to implement such behavior so every time you execute an SQL command you willreceive the result set in a Python list, if there is a need to update or operate directly at the DBlevel you need to make use of the 'SELECT FOR UPDATE' clause on the specific row/record."""try:# Instantiate a connection object with custom logging level and log locationcon=python4DBI(logging_level=logging.DEBUG,logging_file='../python4DBI.log')# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Get cursorcursor=con.cursor()# Do stuff# Close cursorcursor.close()# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 6"""Prepare an SQL statement.It is a good practice before executing an SQL statement to make a validation.This command will return false if the SQL statement is not valid and true otherwise.Note: If the programmer does not validate the SQL statement the DBI always validates the the query beforeexecuting the difference is that on the execute the DBI will raise an error."""try:# Instantiate a connection object with custom logging level and log locationcon=python4DBI(logging_level=logging.DEBUG,logging_file='../python4DBI.log')# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='SELECT * FROM EMPLOYEES'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:# Do stuffpasselse:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 7"""Execute an SQL statement.Note: After executing an SQL statement the programmer can use the row_count to check thenumber of result rows. The 'fetch_all' is not always the best approach since it can resultin a slower fetch imagine that the size of the result set is 100000 rows, that means that thereturn list will be a list of size 100000!In such cases the programmer can use the 'fetch_one' will return only the first row or the'fetch_many'.The are some caveats regarding the way that the DBI works internally since the 4D SQL protocolputs the result page in a buffer every time you execute an SQL statement the DBI will fetch by defaulta page size of 100 rows i.e. imagine if you use execute a statement then a 'fetch_one' internally theDBI will fetch the first page i.e. at least 100 rows, if the programmer knows before hand that it only needsthe first N records than it is more efficient to execute the SQL statement with a page size of N."""try:# Instantiate a connection object with custom logging level and log locationcon=python4DBI(logging_level=logging.DEBUG,logging_file='../python4DBI.log')# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='SELECT * FROM EMPLOYEES'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:# Execute the querycursor.execute(query=query)# Check the resultsifcursor.row_count>0:# Fetch all the resultsresult_rows=cursor.fetch_all()else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 8"""Printing results to the console.Note: Every time you execute the an SQL statement the DBI will create a list of the row headers with tha nameof the DB columns, the programmer can use 'description' for such purposes.The 'print_result' is implemented on the DBI and will provide a 'terminal/console' way to see the results formattedinto a table, and can be usefully for debugging purposes."""try:con=python4DBI(logging_level=logging.DEBUG,logging_file='../python4DBI.log')# Authenticationcon.connect(user='theUser',password='thePassword')ifcon.connected():# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='SELECT * FROM EMPLOYEES'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:# Execute the querycursor.execute(query=query)# Check the resultsifcursor.row_count>0:# Fetch all the resultsresult_rows=cursor.fetch_all()# Print result page to consolecursor.print_result(headers=cursor.description,rows=result_rows)else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassTemplate example 9"""Using params in SQL statements.Using transactions.Note: Normally a DBI will implement only on or tow ways of using param styles in SQL queries, onthis DBI is available qmark, name, format and pyformat.qmark	- Question mark style, e.g. ...WHERE name=?named	- Named style, e.g. ...WHERE name=:nameformat - ANSI C printf format codes, e.g. ...WHERE name=%spyformat - Python extended format codes, e.g. ...WHERE name=%(name)sIt can be used only one type of param style per query!"""try:# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')# Check if the socket is connectedifcon.connected()isTrue:# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='INSERT INTO EMPLOYEES (EmployeeID, City) VALUES(:id, :city)'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:# Start a transactioncursor.start_transaction()foriinrange(1,100):params={'id':str(i),'city':fake.city(),'Date':fake.date()}cursor.execute(query=query,params=params)# Commit the transactioncursor.commit()else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptWarningase:# Handle errorpassexceptErrorase:# Handle errorpassexceptExceptionase:# Handle errorpassExample 1"""Time of execution for multiple results.Note: This examples use the 4D DB that is available at the project level if you wishto do the same tests please use this DB project.If you need to seed the DB with data please use the 'Example 3'."""try:# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')# Check if the socket is connectedifcon.connected()isTrue:# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='SELECT * FROM EMPLOYEES'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:t0=time.time()# Execute the querycursor.execute(query=query)# Check the resultsifcursor.row_count>0:# Fetch all the resultsresult=cursor.fetch_all()t1=time.time()total=round(t1-t0,4)print('Execution time :{}seconds'.format(total))else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptExceptionase:print("Can not continue - reason :{}".format(e))Example 2"""Time of execution for single result."""try:# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')# Check if the socket is connectedifcon.connected()isTrue:# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='SELECT EmployeeID FROM EMPLOYEES WHERE EmployeeID = :id'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:t0=time.time()# Execute the querycursor.execute(query=query,params={'id':'1'})# Check the resultsifcursor.row_count>0:# Fetch all the resultsresult=cursor.fetch_all()t1=time.time()total=round(t1-t0,4)print('Execution time :{}seconds'.format(total))else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptExceptionase:print("Can not continue - reason :{}".format(e))Example 3"""DB data seed."""try:# Instantiate a connection objectcon=python4DBI()# Authenticationcon.connect(user='theUser',password='thePassword')# Check if the socket is connectedifcon.connected()isTrue:# Get cursorcursor=con.cursor()# Prepare the statement i.e check if it OK for executionquery='INSERT INTO EMPLOYEES (EmployeeID, Address1, Address2, City) '\'VALUES (:EmployeeID, :Address1, :Address2, :City)'result=cursor.prepare_statement(query=query)ifresultisFOURD_OK:foriinrange(0,1000):_id=str(i+1)_name=fake.name()_first_name=_name.split()[:1]_last_name=_name.split()[-1:]_address1=fake.address()_address2=fake.address()_zipcode=fake.zipcode()_city=fake.city()_country=fake.country()_phone=fake.phone_number()# Execute the queryparams={'EmployeeID':_id,'Address1':_address1,'Address2':_address2,'City':_city,}cursor.execute(query=query,params=params)else:# Handle wrong statementpass# Close cursorcursor.close()# Close the socket connectioncon.close()exceptExceptionase:print("Can not continue - reason :{}".format(e))