I am trying to adapt the Zend Skeleton App to use an ODBC connection. I am able to set up a PDO connection outside of Zend (same table, server, everything) like this:
new PDO('odbc:DRIVER={iSeries Access ODBC Driver};SYSTEM=<serverName>;HOSTNAME=<serverName>;DATABASE=<databaseName>;',
'<userName>', '<password>');
$r = $this->conn->query('SELECT * FROM <databaseName>.<tableName>');
But when I add this information to the global.php file:
'db' => array(
'driver' => 'Pdo',
'dsn' => 'odbc:DRIVER={iSeries Access ODBC Driver};SYSTEM=<serverName>;HOSTNAME=<serverName>;DATABASE=<databaseName>;',
),
And in local.php:
return array(
'db' => array(
'username' => '<userName>',
'password' => '<password>',
),
);
I get an error that the table is not found:
SQLSTATE[42S02]: Base table or view not found: 0 [IBM][iSeries Access ODBC Driver][DB2 UDB]SQL0204 - <tableName> in <userName - yes you read that right> type *FILE not found.
I believe this is because my prefixed <databaseName>.<tableName> is being wrapped in double quotes when the query runs through Zend. I cannot explain why Zend is looking for my table under userName. However, I cannot get PDO to recognize the table without the prefix, even though I have tried declaring my database in the initialization of the PDO every way I can think of.
Is there a way for PDO to actually pick up the database name so I don't need the prefix? Or is there a way to tell Zend to use the prefix (not lumped in the quotes with the table name)?
Please pardon if I'm using the wrong language here - I get a little lost between Schema, Database, Library, File, Table, etc. when I'm going between SQL and iSeries.
I really appreciate any help you can offer, Zend is new to me.
Not familiar with PDO, as I use ibm_db2, but the database name can be found with the CL command WRKRDBDIRE.
With *SQL naming, an unqualified table name (SELECT * FROM TABLENAME) is implicitly qualified with the user profile name. So if SARAHK is executing the select, it becomes SELECT * FROM SARAHK.TABLENAME. So the error you're seeing indicates that IBM i thinks you have an unqualified table name.
If you could configure the ODBC driver to use *SYSTEM naming, it would use the library list to locate unqualified table names.
I'm an old school RPG programmer, so I'm more familiar with the traditional names; here's a cheat sheet:
Library -> Schema
File -> Table
Member -> No SQL equivalent - use ALIAS
I just went through the process of converting the tutorial to connect to IBM i with the ODBC driver but did not want to specify (a.k.a. hardcode) the library in the connection string. Setting the "NAMING" parameter to '1' (*SYS rather than *SQL) will use the *USRLIBL of the user's connection/profile/JOBD (WRKJOBD INLLIBL( ...) ). If you use *SQL naming, it will take the User ID as the Schema when searching for the table.
My DSN looks like this:
'dsn' => "odbc:DRIVER={iSeries Access ODBC Driver};SYSTEM= your host IP;HOSTNAME=your host;DATABASE=your dbname;NAMING=1"
As long as the table I'm looking for is in the *LIBL, I don't have to worry about schema at the client.
I solved this by finally finding an addition to my DSN that properly specified the library/schema I wanted to work under. This site (http://www.sqlthing.com/HowardsODBCiSeriesFAQ.htm) gave me the parameter DBQ=<libraryName> which finally worked for me after trying DATABASE, DBNAME, and many others.
Now that my library is properly specified in my connection string, I don't need to prefix the table name so my queries work even though I never got Zend to take a schema in the construction of a TableGateway. I'm going to mark this as an answer for now, but if anyone knows how to send a schema name to a new TableGateway I would be happy to change that.
Related
I need make a query for a postgresdb without identify accents (á, í,ö, etc).
I'm already use Knex.js as query builder, and postgresql have a unaccent extension that works fine in sql querys directly to db, but in my code i use knex and unaccent function throws error in querys.
Can anyone help me, ¿is possible make querys with knex.js that use unaccent function of postgresql?
My solution is to process the string before submitting the query using the following code:
const normalize = (str) => str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
console.log(normalize('Ấ Á Ắ Ạ Ê')) -> 'A A A A A'.
Or if you use postgresql version 13 or later it already supports that functionality.
select normalize('hồ, phố, ầ', NFC) → 'ho, pho, a' -- NFC (the default), NFD, NFKC, or NFKD.
Document: https://www.postgresql.org/docs/13/functions-string.html
I adapted my code from the instructions here.
open FSharp.Data.Sql
let [<Literal>] connection_str = "Server=localhost;Port=3306;SSL Mode=None;Uid=<UID>;Pwd=<PWD>;Database=<DB>"
type provider = SqlDataProvider<Common.DatabaseProviderTypes.MYSQL, connection_str>
let context = provider.GetDataContext()
context.Procedures.SpGetFrontContracts.Invoke(1)
Intellisense works until the period after SpGetFrontContracts. After that, nothing. Trying to compile, I get:
Error FS0039 The field, constructor or member 'Invoke' is not defined.
I am otherwise able to connect to the database and insert and query data, as long as I stick to tables and views.
SpGetFrontContracts is a valid stored procedure in my database (its actual name is sp_get_front_contracts, but the type provider seems to remove underscores). I can run it successfully using HeidiSQL. In case it's useful, here's the create code:
CREATE DEFINER=`<UID>`#`localhost` PROCEDURE `sp_get_front_contracts`(
IN `Group` INT
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
SELECT p.DateTime, p.Contract, p.Volume, c.Name
FROM tbl_contract_price_data p
INNER JOIN tbl_contracts c on p.Contract = c.ID
WHERE c.`Group` = `Group`
ORDER BY p.DateTime
LIMIT 1000;
END
I tried creating a simpler sproc that was named 'test', took no parameters, and simply ran a select statement. It showed up in the type provider under Procedures, but again I could not call Invoke on it.
My best guess is that Invoke is being inherited from some namespace or assembly reference I don't have, so I'm currently looking through the SqlProvider source to try to figure out what it might be. I'm currently referencing:
FSharp.Core
FSharp.Data
FSharp.Data.SqlProvider
mscorlib
System
System.Core
System.Data
System.Numerics
System.ValueTyple
System.Xml.Linq
Thank you for any suggestions.
Edit: It looks like the action is in SqlDesignTime.fs in a function called generateSprocMethod that starts on line 346. I'll try to figure out what's going on in there.
Edit: After three days banging my head against this, I gave up and just used MySQL Connector/NET.
I'm not sure about your underlying data or structures, but I know these are two other (correct) ways to solve it:
WHERE c.`Group` = `Group` -- what you have.
-- possible corrections:
WHERE c.`Group` = p.`Group` -- did you mean this?
WHERE c.`Group` = "Group" -- or this?
Is there are way to detect what type of database currenlty is in use as project datasource?
Because I need to get some inner scripts information. And, in case of simple .EAP project, SQL-query would look like (because of Access db in use):
_repository.SQLQuery(string.Format(#"SELECT * FROM t_script WHERE Notes LIKE '*Script Name=""{0}""*';", scriptName));
But, in case of SQL server I need to execute (as you already guessed I bet) slighly different written query:
_repository.SQLQuery(string.Format(#"SELECT * FROM t_script WHERE Notes LIKE '%Script Name=""{0}""%';", scriptName));
So, is it possible?
UPD:
I found one option - looks like there are _repository.ConnectionString property which could be parsed
"SparxEaDatabase --- DBType=1;Connect=Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SparxEaDatabase;Data Source=SOURCENAME;LazyLoad=1;"
Is there are more?
I would just look into Repository.RepositoryType. This will return for Example: JET, MYSQL, or SQLSVR.
I'm converting some RDO code to ODBC Provider code in .NET.
The problem is parameter names were not specified in the orignal code, but param values were retrieved by parameter name after the command was executed.
Is there anyway to have parameter names populated by the provider once the command is executed so calling code can access params by name.
Let me show you an example of the declaration of param and accessing of it.
With rdqryClntBasic
.Parameters.Add(.CreateParameter) : .Parameters(0).Direction = ParameterDirection.Input
.Parameters(0).DbType = DbType.String
.Parameters(0).Value = sClntProdCd
End With
.EffectiveDate = ToDate(rdqryClntBasic.Parameters("dtEffDt").Value)
You can now see how this "used to work in RDO/VB". For some reason it would accept this and know what the param names were after execution. I imagine it had to do another round trip to the db to get this info.
Is there anyway to mimic this behaviour in .NET for ODBC Provider (using Oracle)? Or am I stuck manually specifying the param names in the code (I understand this is the better option, but wondering what the alternative is to match the original code as closely as possible).
No, parameters in ODBC are positional not by name.
I have a large Openldap directory. In the directory the display name property for every is filled but i need to modify these entry and make it like "givenName + + sn". Is there are way i can do it directly in the directory just like sql queries (update query). I have read about the ldapmodify but could not find the way to use it like this.
Any help in this regard will be appreciated.
There is no way to do this with a single LDAP API call. You'll always have to use one LDAP search operation to get givenname and sn attributes, and one LDAP modify operation to modify the displayName attribute.
If you use the command line ldaptools "ldapsearch" and "ldapmodify", you can do this easily with some shell scripting, but you'll have to be careful: sometimes ldapsearch(1) can return LDIF data in base64 format, with UTF-8 strings that contain characters beyond ascii. For instance: 'sn:: Base64data' (note the double ':')
So, if I were you I would use a simple script in my language of choice, that has an LDAP API, instead of using shell commands. This would save me the troubles of base64 decoding that the ldaptools sometimes impose.
For instance, with php-cli, your script would be roughly like this (perhaps some more error checking would be appropriate):
<?php
$ldap = ldap_connect('host');
ldap_bind($ldap, ...);
$sr = ldap_search($ldap, 'ou=people,...', 'objectclass=*');
$entries= ldap_get_entries($ldap, $sr);
for($i=0; $i<$entries['count']; $i++) {
$modify = array('displayname' => $entries[$i]['givenname'] . ' ' . $entries[$i]['sn']);
ldap_modify($ldap, $entries[$i]['dn'], $modify);
}
Addendum: if you want to keep this data up to date without any intervention, you will probably need to use a specialized OpenLDAP module that keeps "virtual" attributes, or even a virtual directory, such as Penrose or Oracle Virtual Directory, on top of OpenLDAP. However this might be overkill for a simple concatenation of attributes.