Skip to content

Commit 3c4b9b4

Browse files
Improvements | SQLServerParameterMetadata improvements with improved code coverage (#973)
1 parent 50a9530 commit 3c4b9b4

File tree

2 files changed

+134
-141
lines changed

2 files changed

+134
-141
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java

+101-141
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ private void parseQueryMeta(ResultSet rsQueryMeta) throws SQLServerException {
254254
SQLServerException.getErrString("R_metaDataErrorForParameter"));
255255
Object[] msgArgs = {paramOrdinal};
256256
SQLServerException.makeFromDriverError(con, stmtParent,
257-
form.format(msgArgs) + " " + e.toString(), null, false);
257+
form.format(msgArgs) + " " + e.getMessage(), null, false);
258258
}
259259
}
260260
} else
@@ -547,8 +547,8 @@ private void checkClosed() throws SQLServerException {
547547
* the procedure name
548548
* @throws SQLServerException
549549
*/
550+
@SuppressWarnings("serial")
550551
SQLServerParameterMetaData(SQLServerPreparedStatement st, String sProcString) throws SQLServerException {
551-
552552
assert null != st;
553553
stmtParent = st;
554554
con = st.connection;
@@ -612,9 +612,8 @@ private void checkClosed() throws SQLServerException {
612612

613613
if (con.getServerMajorVersion() >= SQL_SERVER_2012_VERSION) {
614614
// new implementation for SQL verser 2012 and above
615-
String preparedSQL = con.replaceParameterMarkers((stmtParent).userSQL,
616-
(stmtParent).userSQLParamPositions, (stmtParent).inOutParam,
617-
(stmtParent).bReturnValueSyntax);
615+
String preparedSQL = con.replaceParameterMarkers(stmtParent.userSQL,
616+
stmtParent.userSQLParamPositions, stmtParent.inOutParam, stmtParent.bReturnValueSyntax);
618617

619618
try (SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con
620619
.prepareCall("exec sp_describe_undeclared_parameters ?")) {
@@ -680,9 +679,9 @@ private void checkClosed() throws SQLServerException {
680679
catch (SQLServerException e) {
681680
throw e;
682681
} catch (SQLException e) {
683-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
682+
SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false);
684683
} catch (StringIndexOutOfBoundsException e) {
685-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
684+
SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false);
686685
}
687686
}
688687

@@ -703,58 +702,66 @@ public <T> T unwrap(Class<T> iface) throws SQLException {
703702
return t;
704703
}
705704

706-
private Map<String, Object> getParameterInfo(int param) throws SQLServerException {
707-
boolean paramFound = false;
708-
if ((stmtParent).bReturnValueSyntax && isTVP) {
709-
paramFound = procMetadata.size() >= param;
710-
if (paramFound) {
711-
return procMetadata.get(param - 1);
712-
}
705+
private Map<String, Object> getParameterInfo(int param) {
706+
if (stmtParent.bReturnValueSyntax && isTVP) {
707+
return procMetadata.get(param - 1);
713708
} else {
714709
// Note row 1 is the 'return value' meta data
715-
paramFound = procMetadata.size() > param;
716-
if (paramFound) {
717-
return procMetadata.get(param);
718-
}
710+
return procMetadata.get(param);
719711
}
720-
if (!paramFound) {
712+
}
713+
714+
private boolean isValidParamProc(int n) {
715+
// Note row 1 is the 'return value' meta data
716+
return ((stmtParent.bReturnValueSyntax && isTVP && procMetadata.size() >= n) || procMetadata.size() > n);
717+
}
718+
719+
private boolean isValidParamQuery(int n) {
720+
return (null != queryMetaMap && queryMetaMap.containsKey(n));
721+
}
722+
723+
/**
724+
* Checks if the @param passed is valid for either procedure metadata or query metadata.
725+
*
726+
* @param param
727+
* @throws SQLServerException
728+
*/
729+
private void checkParam(int param) throws SQLServerException {
730+
// Check if Procedure Metadata is not available
731+
if (null == procMetadata) {
732+
// Check if Query Metadata is also not available
733+
if (!isValidParamQuery(param)) {
734+
SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"),
735+
null, false);
736+
}
737+
} else if (!isValidParamProc(param)) {
738+
// Throw exception if @param index not found
721739
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidParameterNumber"));
722740
Object[] msgArgs = {param};
723741
SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs), null, false);
724742
}
725-
return null;
726-
}
727-
728-
private void checkParam(int n) throws SQLServerException {
729-
if (!queryMetaMap.containsKey(n)) {
730-
SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"),
731-
null, false);
732-
}
733743
}
734744

735745
@Override
736746
public String getParameterClassName(int param) throws SQLServerException {
737747
checkClosed();
748+
checkParam(param);
738749
try {
739-
if (procMetadata == null) {
740-
// PreparedStatement.
741-
checkParam(param);
750+
if (null == procMetadata) {
742751
return queryMetaMap.get(param).parameterClassName;
743752
} else {
744-
JDBCType jdbcType = JDBCType.of((short) getParameterInfo(param).get("DATA_TYPE"));
745-
return jdbcType.className();
753+
return JDBCType.of((short) getParameterInfo(param).get("DATA_TYPE")).className();
746754
}
747-
} catch (SQLException e) {
748-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
755+
} catch (SQLServerException e) {
756+
SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false);
749757
return null;
750758
}
751759
}
752760

753761
@Override
754762
public int getParameterCount() throws SQLServerException {
755763
checkClosed();
756-
if (procMetadata == null) {
757-
// PreparedStatement
764+
if (null == procMetadata) {
758765
return queryMetaMap.size();
759766
} else {
760767
// Row 1 is Return Type metadata
@@ -765,170 +772,123 @@ public int getParameterCount() throws SQLServerException {
765772
@Override
766773
public int getParameterMode(int param) throws SQLServerException {
767774
checkClosed();
768-
try {
769-
if (procMetadata == null) {
770-
checkParam(param);
771-
// if it is not a stored proc, the param can only be input.
775+
checkParam(param);
776+
if (null == procMetadata) {
777+
// if it is not a stored procedure, the @param can only be input.
778+
return parameterModeIn;
779+
} else {
780+
int n = (int) getParameterInfo(param).get("COLUMN_TYPE");
781+
if (n == 1)
772782
return parameterModeIn;
773-
} else {
774-
int n = (int) getParameterInfo(param).get("COLUMN_TYPE");
775-
switch (n) {
776-
case 1:
777-
return parameterModeIn;
778-
case 2:
779-
return parameterModeOut;
780-
default:
781-
return parameterModeUnknown;
782-
}
783-
}
784-
} catch (SQLException e) {
785-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
786-
return parameterModeUnknown;
783+
else if (n == 2)
784+
return parameterModeOut;
785+
else
786+
return parameterModeUnknown;
787787
}
788788
}
789789

790790
@Override
791791
public int getParameterType(int param) throws SQLServerException {
792792
checkClosed();
793+
checkParam(param);
793794
int parameterType = 0;
794-
try {
795-
if (procMetadata == null) {
796-
// PreparedStatement.
797-
checkParam(param);
798-
parameterType = queryMetaMap.get(param).parameterType;
799-
} else {
800-
Map<String, Object> info = getParameterInfo(param);
801-
if (null != info) {
802-
parameterType = (short) info.get("DATA_TYPE");
803-
}
804-
}
805-
if (0 != parameterType) {
806-
switch (parameterType) {
807-
case microsoft.sql.Types.DATETIME:
808-
case microsoft.sql.Types.SMALLDATETIME:
809-
parameterType = SSType.DATETIME2.getJDBCType().asJavaSqlType();
810-
break;
811-
case microsoft.sql.Types.MONEY:
812-
case microsoft.sql.Types.SMALLMONEY:
813-
parameterType = SSType.DECIMAL.getJDBCType().asJavaSqlType();
814-
break;
815-
case microsoft.sql.Types.GUID:
816-
parameterType = SSType.CHAR.getJDBCType().asJavaSqlType();
817-
break;
818-
default:
819-
break;
820-
}
795+
if (null == procMetadata) {
796+
parameterType = queryMetaMap.get(param).parameterType;
797+
} else {
798+
parameterType = (short) getParameterInfo(param).get("DATA_TYPE");
799+
}
800+
if (0 != parameterType) {
801+
switch (parameterType) {
802+
case microsoft.sql.Types.DATETIME:
803+
case microsoft.sql.Types.SMALLDATETIME:
804+
parameterType = SSType.DATETIME2.getJDBCType().asJavaSqlType();
805+
break;
806+
case microsoft.sql.Types.MONEY:
807+
case microsoft.sql.Types.SMALLMONEY:
808+
parameterType = SSType.DECIMAL.getJDBCType().asJavaSqlType();
809+
break;
810+
case microsoft.sql.Types.GUID:
811+
parameterType = SSType.CHAR.getJDBCType().asJavaSqlType();
812+
break;
813+
default:
814+
break;
821815
}
822-
return parameterType;
823-
} catch (SQLException e) {
824-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
825-
return 0;
826816
}
817+
return parameterType;
827818
}
828819

829820
@Override
830821
public String getParameterTypeName(int param) throws SQLServerException {
831822
checkClosed();
832-
try {
833-
if (procMetadata == null) {
834-
// PreparedStatement.
835-
checkParam(param);
836-
return queryMetaMap.get(param).parameterTypeName;
837-
} else {
838-
return getParameterInfo(param).get("TYPE_NAME").toString();
839-
}
840-
} catch (SQLException e) {
841-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
842-
return null;
823+
checkParam(param);
824+
if (null == procMetadata) {
825+
return queryMetaMap.get(param).parameterTypeName;
826+
} else {
827+
return getParameterInfo(param).get("TYPE_NAME").toString();
843828
}
844829
}
845830

846831
@Override
847832
public int getPrecision(int param) throws SQLServerException {
848833
checkClosed();
849-
try {
850-
if (procMetadata == null) {
851-
// PreparedStatement.
852-
checkParam(param);
853-
return queryMetaMap.get(param).precision;
854-
} else {
855-
int nPrec = (int) getParameterInfo(param).get("PRECISION");
856-
return nPrec;
857-
}
858-
} catch (SQLException e) {
859-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
860-
return 0;
834+
checkParam(param);
835+
if (null == procMetadata) {
836+
return queryMetaMap.get(param).precision;
837+
} else {
838+
return (int) getParameterInfo(param).get("PRECISION");
861839
}
862840
}
863841

864842
@Override
865843
public int getScale(int param) throws SQLServerException {
866844
checkClosed();
867-
try {
868-
if (procMetadata == null) {
869-
// PreparedStatement.
870-
checkParam(param);
871-
return queryMetaMap.get(param).scale;
872-
} else {
873-
int nScale = (int) getParameterInfo(param).get("SCALE");
874-
return nScale;
875-
}
876-
} catch (SQLException e) {
877-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
878-
return 0;
845+
checkParam(param);
846+
if (null == procMetadata) {
847+
return queryMetaMap.get(param).scale;
848+
} else {
849+
return (int) getParameterInfo(param).get("SCALE");
879850
}
880851
}
881852

882853
@Override
883854
public int isNullable(int param) throws SQLServerException {
884855
checkClosed();
885-
try {
886-
if (procMetadata == null) {
887-
// PreparedStatement.
888-
checkParam(param);
889-
return queryMetaMap.get(param).isNullable;
890-
} else {
891-
int nNull = (int) getParameterInfo(param).get("NULLABLE");
892-
if (nNull == 1)
893-
return parameterNullable;
894-
if (nNull == 0)
895-
return parameterNoNulls;
896-
return parameterNullableUnknown;
897-
}
898-
} catch (SQLException e) {
899-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
900-
return parameterNoNulls;
856+
checkParam(param);
857+
if (procMetadata == null) {
858+
return queryMetaMap.get(param).isNullable;
859+
} else {
860+
return (int) getParameterInfo(param).get("NULLABLE");
901861
}
902862
}
903863

904864
/**
905865
* Returns if a supplied parameter index is valid.
906866
*
907867
* @param param
908-
* the param index
868+
* the @param index
909869
* @throws SQLServerException
910870
* when an error occurs
911871
* @return boolean
912872
*/
913873
@Override
914874
public boolean isSigned(int param) throws SQLServerException {
915875
checkClosed();
876+
checkParam(param);
916877
try {
917-
if (procMetadata == null) {
918-
// PreparedStatement.
919-
checkParam(param);
878+
if (null == procMetadata) {
920879
return queryMetaMap.get(param).isSigned;
921880
} else {
922881
return JDBCType.of((short) getParameterInfo(param).get("DATA_TYPE")).isSigned();
923882
}
924883
} catch (SQLException e) {
925-
SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false);
884+
SQLServerException.makeFromDriverError(con, stmtParent, e.getMessage(), null, false);
926885
return false;
927886
}
928887
}
929888

930889
String getTVPSchemaFromStoredProcedure(int param) throws SQLServerException {
931890
checkClosed();
891+
checkParam(param);
932892
return (String) getParameterInfo(param).get("SS_TYPE_SCHEMA_NAME");
933893
}
934894
}

0 commit comments

Comments
 (0)